Example #1
0
def optimize():
    Graphs.startGraph()

    # First pass.
    if _progress:
        info("PASS 1:")

    makeOptimizationPass(False)
    VariableRegistry.considerCompletion()
    finished = makeOptimizationPass(False)

    # Demote to bytecode if now.
    for module in ModuleRegistry.getDoneUserModules():
        if module.isPythonShlibModule():
            continue

        if module.mode == "bytecode":
            demoteCompiledModuleToBytecode(module)

    # Second, endless pass.
    if _progress:
        info("PASS 2..:")

    while not finished:
        finished = makeOptimizationPass(True)

    Graphs.endGraph()
Example #2
0
    def removeUserVariable(self, variable):
        assert variable in self.providing.values(), (self.providing, variable)

        del self.providing[variable.getName()]

        assert not variable.isParameterVariable() or \
               variable.getOwner() is not self

        VariableRegistry.removeVariableUsage(variable, self)
Example #3
0
    def removeUserVariable(self, variable):
        assert variable in self.providing.values(), (self.providing, variable)

        del self.providing[variable.getName()]

        assert not variable.isParameterVariable() or \
               variable.getOwner() is not self

        VariableRegistry.removeVariableUsage(variable, self)
Example #4
0
def optimize():
    # This is somewhat complex with many cases, pylint: disable=R0912

    while True:
        finished = True

        ModuleRegistry.startTraversal()

        while True:
            current_module = ModuleRegistry.nextModule()

            if current_module is None:
                break

            if _progress:
                printLine(
                    """\
Optimizing module '{module_name}', {remaining:d} more modules to go \
after that. Memory usage {memory}:""".format(
                        module_name = current_module.getFullName(),
                        remaining   = ModuleRegistry.remainingCount(),
                        memory      = Utils.getHumanReadableProcessMemoryUsage()
                    )
                )

            if current_module.isPythonShlibModule():
                optimizeShlibModule(current_module)
            else:
                changed = optimizePythonModule(current_module)

                if changed:
                    finished = False

        # Unregister collection traces from now unused code.
        for current_module in ModuleRegistry.getDoneModules():
            if not current_module.isPythonShlibModule():
                for function in current_module.getUnusedFunctions():
                    VariableRegistry.updateFromCollection(
                        old_collection = function.constraint_collection,
                        new_collection = None
                    )

                    function.constraint_collection = None

        if not VariableRegistry.complete:
            VariableRegistry.complete = True

            finished = False

        for current_module in ModuleRegistry.getDoneModules():
            if not current_module.isPythonShlibModule():
                optimizeVariables(current_module)

        if finished:
            break
Example #5
0
def makeOptimizationPass(initial_pass):
    """ Make a single pass for optimization, indication potential completion.

    """
    finished = True

    ModuleRegistry.startTraversal()

    if _progress:
        if initial_pass:
            printLine("Initial optimization pass.")
        else:
            printLine("Next global optimization pass.")

    while True:
        current_module = ModuleRegistry.nextModule()

        if current_module is None:
            break

        if _progress:
            _traceProgress(current_module)

        # The tag set is global, so it can react to changes without context.
        # pylint: disable=W0603
        global tag_set
        tag_set = TagSet()

        changed = optimizeModule(current_module)

        if changed:
            finished = False

    # Unregister collection traces from now unused code, dropping the trace
    # collections of functions no longer used.
    for current_module in ModuleRegistry.getDoneModules():
        if current_module.isCompiledPythonModule():
            for function in current_module.getUnusedFunctions():
                VariableRegistry.updateFromCollection(
                    old_collection = function.constraint_collection,
                    new_collection = None
                )

                function.constraint_collection = None

    for current_module in ModuleRegistry.getDoneModules():
        optimizeVariables(current_module)

    return finished
Example #6
0
def optimizeUnusedClosureVariables(function_body):
    for closure_variable in function_body.getClosureVariables():
        # print "VAR", closure_variable

        variable_traces = function_body.constraint_collection.getVariableTraces(
            variable=closure_variable)

        empty = areEmptyTraces(variable_traces)
        if empty:
            signalChange("var_usage",
                         function_body.getSourceReference(),
                         message="Remove unused closure variable.")

            function_body.removeClosureVariable(closure_variable)
        else:
            read_only = areReadOnlyTraces(variable_traces)

            if read_only:
                global_trace = VariableRegistry.getGlobalVariableTrace(
                    closure_variable)

                if global_trace is not None:
                    if not global_trace.hasWritesOutsideOf(function_body):
                        function_body.demoteClosureVariable(closure_variable)

                        signalChange(
                            "var_usage",
                            function_body.getSourceReference(),
                            message=
                            "Turn read-only usage of unassigned closure variable to local variable."
                        )
Example #7
0
def optimizeUnusedClosureVariables(function_body):
    for closure_variable in function_body.getClosureVariables():
        # print "VAR", closure_variable

        variable_traces = function_body.constraint_collection.getVariableTraces(
            variable = closure_variable
        )

        empty = areEmptyTraces(variable_traces)
        if empty:
            signalChange(
                "var_usage",
                function_body.getSourceReference(),
                message = "Remove unused closure variable."
            )

            function_body.removeClosureVariable(closure_variable)
        else:
            read_only = areReadOnlyTraces(variable_traces)

            if read_only:
                global_trace = VariableRegistry.getGlobalVariableTrace(closure_variable)

                if global_trace is not None:
                    if not global_trace.hasWritesOutsideOf(function_body):
                        function_body.demoteClosureVariable(closure_variable)

                        signalChange(
                            "var_usage",
                            function_body.getSourceReference(),
                            message = "Turn read-only usage of unassigned closure variable to local variable."
                        )
Example #8
0
    def demoteClosureVariable(self, variable):
        assert variable.isLocalVariable()

        self.taken.remove(variable)

        assert variable.getOwner() is not self

        new_variable = Variables.LocalVariable(
            owner=self, variable_name=variable.getName())

        self.providing[variable.getName()] = new_variable

        updateVariableUsage(provider=self,
                            old_variable=variable,
                            new_variable=new_variable)

        VariableRegistry.addVariableUsage(new_variable, self)
Example #9
0
    def demoteClosureVariable(self, variable):
        assert variable.isLocalVariable()

        self.taken.remove(variable)

        assert variable.getOwner() is not self

        new_variable = Variables.LocalVariable(
            owner         = self,
            variable_name = variable.getName()
        )

        self.providing[variable.getName()] = new_variable

        updateVariableUsage(
            provider     = self,
            old_variable = variable,
            new_variable = new_variable
        )

        VariableRegistry.removeVariableUsage(variable, self)
        VariableRegistry.addVariableUsage(new_variable, self)
Example #10
0
    def computeExpression(self, constraint_collection):
        variable = self.variable

        assert variable is not None

        self.variable_trace = constraint_collection.getVariableCurrentTrace(
            variable = variable
        )

        replacement = self.variable_trace.getReplacementNode(self)

        if replacement is not None:
            return (
                replacement,
                "new_expression",
                "Value propagated for '%s' from '%s'." % (
                    self.variable.getName(),
                    replacement.getSourceReference().getAsString()
                )
            )

        self.global_trace = VariableRegistry.getGlobalVariableTrace(variable)

        # TODO: Maybe local variables are factored into this strangely.
        if self.global_trace is None and variable.isModuleVariable():
            constraint_collection.assumeUnclearLocals()
        elif (variable.isModuleVariable() and not self.global_trace.hasDefiniteWrites() ) or \
             variable.isMaybeLocalVariable():
            if self.variable_name in Builtins.builtin_exception_names:
                from .BuiltinRefNodes import ExpressionBuiltinExceptionRef

                new_node = ExpressionBuiltinExceptionRef(
                    exception_name = self.variable_name,
                    source_ref     = self.getSourceReference()
                )

                change_tags = "new_builtin_ref"
                change_desc = """\
Module variable '%s' found to be built-in exception reference.""" % (
                    self.variable_name
                )
            elif self.variable_name in Builtins.builtin_names and \
                 self.variable_name != "pow":
                from .BuiltinRefNodes import ExpressionBuiltinRef

                new_node = ExpressionBuiltinRef(
                    builtin_name = self.variable_name,
                    source_ref   = self.getSourceReference()
                )

                change_tags = "new_builtin_ref"
                change_desc = """\
Module variable '%s' found to be built-in reference.""" % (
                    self.variable_name
                )
            elif self.variable_name == "__name__":
                new_node = ExpressionConstantRef(
                    constant   = variable.getOwner().getParentModule().\
                                   getFullName(),
                    source_ref = self.getSourceReference()
                )

                change_tags = "new_constant"
                change_desc = """\
Replaced read-only module attribute '__name__' with constant value."""
            elif self.variable_name == "__package__":
                new_node = ExpressionConstantRef(
                    constant   = variable.getOwner().getPackage(),
                    source_ref = self.getSourceReference()
                )

                change_tags = "new_constant"
                change_desc = """\
Replaced read-only module attribute '__package__' with constant value."""
            else:
                self.variable_trace.addUsage()

                # Probably should give a warning once about it.
                new_node = self
                change_tags = None
                change_desc = None

            return new_node, change_tags, change_desc

        self.variable_trace.addUsage()

        return self, None, None
Example #11
0
 def updateFromCollection(self, old_collection):
     VariableRegistry.updateFromCollection(old_collection, self)
Example #12
0
    def computeStatement(self, constraint_collection):
        # This is very complex stuff, pylint: disable=R0912

        # TODO: Way too ugly to have global trace kinds just here, and needs to
        # be abstracted somehow. But for now we let it live here: pylint: disable=R0911,R0915

        # Assignment source may re-compute here:
        constraint_collection.onExpression(self.getAssignSource())
        source = self.getAssignSource()

        # No assignment will occur, if the assignment source raises, so strip it
        # away.
        if source.willRaiseException(BaseException):

            result = makeStatementExpressionOnlyReplacementNode(expression=source, node=self)

            return (
                result,
                "new_raise",
                """\
Assignment raises exception in assigned value, removed assignment.""",
            )

        variable_ref = self.getTargetVariableRef()
        variable = variable_ref.getVariable()

        # Not allowed anymore at this point.
        assert variable is not None

        # Assigning from and to the same variable, can be optimized away
        # immediately, there is no point in doing it. Exceptions are of course
        # module variables that collide with built-in names.
        if not variable.isModuleVariable() and source.isExpressionVariableRef() and source.getVariable() == variable:

            # A variable access that has a side effect, must be preserved,
            # so it can e.g. raise an exception, otherwise we can be fully
            # removed.
            if source.mayHaveSideEffects():
                result = makeStatementExpressionOnlyReplacementNode(expression=source, node=self)

                return (
                    result,
                    "new_statements",
                    """\
Reduced assignment of variable from itself to access of it.""",
                )
            else:
                return (
                    None,
                    "new_statements",
                    """\
Removed assignment of variable from itself which is known to be defined.""",
                )

        # If the assignment source has side effects, we can simply evaluate them
        # beforehand, we have already visited and evaluated them before.
        if source.isExpressionSideEffects():
            statements = [
                makeStatementExpressionOnlyReplacementNode(side_effect, self) for side_effect in source.getSideEffects()
            ]

            statements.append(self)

            parent = self.parent
            result = makeStatementsSequenceReplacementNode(statements=statements, node=self)
            result.parent = parent

            # Need to update it.
            self.setAssignSource(source.getExpression())
            source = self.getAssignSource()

            return (
                result,
                "new_statements",
                """\
Side effects of assignments promoted to statements.""",
            )

        # Set-up the trace to the trace collection, so future references will
        # find this assignment.
        self.variable_trace = constraint_collection.onVariableSet(assign_node=self)

        global_trace = VariableRegistry.getGlobalVariableTrace(variable)

        if global_trace is not None and Options.isExperimental():
            last_trace = global_trace.getMatchingAssignTrace(self)

            if last_trace is not None:
                if variable.isLocalVariable() or variable.isTempVariable():
                    if source.isCompileTimeConstant():

                        # Can safely forward propagate only non-mutable constants.
                        if not source.isMutable():
                            provider = self.getParentVariableProvider()

                            if variable.isTempVariable() or (
                                not provider.isUnoptimized() and not provider.isClassDictCreation()
                            ):

                                if last_trace.hasDefiniteUsages():
                                    self.variable_trace.setReplacementNode(lambda usage: source.makeClone())
                                    propagated = True
                                else:
                                    propagated = False

                                if not last_trace.hasPotentialUsages() and not last_trace.hasNameUsages():
                                    # This limitation may fall later.
                                    if not variable.isSharedLogically():

                                        if not last_trace.getPrevious().isUninitTrace():
                                            # TODO: We could well decide, if that's even necessary.
                                            result = StatementDelVariable(
                                                variable_ref=self.getTargetVariableRef(),
                                                tolerant=True,
                                                source_ref=self.getSourceReference(),
                                            )
                                        else:
                                            result = None

                                        return (
                                            result,
                                            "new_statements",
                                            "Dropped %s assignment statement to '%s'."
                                            % (
                                                "propagated" if propagated else "dead",
                                                self.getTargetVariableRef().getVariableName(),
                                            ),
                                        )
                        else:
                            # Something might be possible still.

                            pass
                    elif (
                        Options.isExperimental()
                        and source.isExpressionFunctionCreation()
                        and not source.getFunctionRef().getFunctionBody().isGenerator()
                        and not source.getFunctionRef().getFunctionBody().isClassDictCreation()
                        and not source.getDefaults()
                        and not source.getKwDefaults()
                        and not source.getAnnotations()
                    ):
                        # TODO: These are very mutable, right?

                        provider = self.getParentVariableProvider()

                        if variable.isTempVariable() or (
                            not provider.isUnoptimized() and not provider.isClassDictCreation()
                        ):

                            # This limitation may fall later.
                            if not variable.isSharedLogically():

                                if (
                                    last_trace.getDefiniteUsages() <= 1
                                    and not last_trace.hasPotentialUsages()
                                    and not last_trace.hasNameUsages()
                                ):

                                    if last_trace.getDefiniteUsages() == 1:
                                        self.variable_trace.setReplacementNode(lambda usage: source.makeClone())
                                        propagated = True
                                    else:
                                        propagated = False

                                    if not last_trace.getPrevious().isUninitTrace():
                                        # TODO: We could well decide, if that's even necessary.
                                        result = StatementDelVariable(
                                            variable_ref=self.getTargetVariableRef(),
                                            tolerant=True,
                                            source_ref=self.getSourceReference(),
                                        )
                                    else:
                                        result = None

                                    return (
                                        result,
                                        "new_statements",
                                        "Dropped %s assignment statement to '%s'."
                                        % (
                                            "propagated" if propagated else "dead",
                                            self.getTargetVariableRef().getVariableName(),
                                        ),
                                    )

                    else:
                        # More cases thinkable.
                        pass

        return self, None, None
Example #13
0
def optimize():
    # This is somewhat complex with many cases, pylint: disable=R0912

    # We maintain this globally to make it accessible, pylint: disable=W0603
    global graph

    if Options.shouldCreateGraph():

        try:
            from graphviz import Digraph # pylint: disable=F0401,I0021
            graph = Digraph('G')
        except ImportError:
            warning("Cannot import graphviz module, no graphing capability.")

    while True:
        finished = True

        ModuleRegistry.startTraversal()

        while True:
            current_module = ModuleRegistry.nextModule()

            if current_module is None:
                break

            if _progress:
                printLine(
                    """\
Optimizing module '{module_name}', {remaining:d} more modules to go \
after that. Memory usage {memory}:""".format(
                        module_name = current_module.getFullName(),
                        remaining   = ModuleRegistry.remainingCount(),
                        memory      = MemoryUsage.getHumanReadableProcessMemoryUsage()
                    )
                )

            if current_module.isPythonShlibModule():
                optimizeShlibModule(current_module)
            else:
                changed = optimizePythonModule(current_module)

                if changed:
                    finished = False

        # Unregister collection traces from now unused code.
        for current_module in ModuleRegistry.getDoneModules():
            if not current_module.isPythonShlibModule():
                for function in current_module.getUnusedFunctions():
                    VariableRegistry.updateFromCollection(
                        old_collection = function.constraint_collection,
                        new_collection = None
                    )

                    function.constraint_collection = None

        if VariableRegistry.considerCompletion():
            finished = False

        for current_module in ModuleRegistry.getDoneModules():
            if not current_module.isPythonShlibModule():
                optimizeVariables(current_module)

        if finished:
            break


    if graph is not None:
        graph.engine = "dot"
        graph.graph_attr["rankdir"] = "TB"
        graph.render("something.dot")

        printLine(graph.source)
Example #14
0
 def updateFromCollection(self, old_collection):
     VariableRegistry.updateFromCollection(old_collection, self)
Example #15
0
    def computeExpression(self, constraint_collection):
        variable = self.variable

        assert variable is not None

        self.variable_trace = constraint_collection.getVariableCurrentTrace(
            variable=variable)

        replacement = self.variable_trace.getReplacementNode(self)

        if replacement is not None:
            constraint_collection.signalChange(
                "new_expression", self.source_ref,
                "Value propagated for '%s' from '%s'." %
                (self.variable.getName(),
                 replacement.getSourceReference().getAsString()))

            # Need to compute the replacement still.
            return replacement.computeExpression(constraint_collection)

        if not self.variable_trace.mustHaveValue():
            # TODO: This could be way more specific surely.
            constraint_collection.onExceptionRaiseExit(BaseException)

        self.global_trace = VariableRegistry.getGlobalVariableTrace(variable)

        # TODO: Maybe local variables are factored into this strangely.
        if self.global_trace is None and variable.isModuleVariable():
            constraint_collection.assumeUnclearLocals()
        elif (variable.isModuleVariable() and not self.global_trace.hasDefiniteWrites() ) or \
             variable.isMaybeLocalVariable():
            if self.variable_name in Builtins.builtin_exception_names:
                from .BuiltinRefNodes import ExpressionBuiltinExceptionRef

                new_node = ExpressionBuiltinExceptionRef(
                    exception_name=self.variable_name,
                    source_ref=self.getSourceReference())

                change_tags = "new_builtin_ref"
                change_desc = """\
Module variable '%s' found to be built-in exception reference.""" % (
                    self.variable_name)
            elif self.variable_name in Builtins.builtin_names and \
                 self.variable_name != "pow":
                from .BuiltinRefNodes import ExpressionBuiltinRef

                new_node = ExpressionBuiltinRef(
                    builtin_name=self.variable_name,
                    source_ref=self.getSourceReference())

                change_tags = "new_builtin_ref"
                change_desc = """\
Module variable '%s' found to be built-in reference.""" % (self.variable_name)
            elif self.variable_name == "__name__":
                new_node = ExpressionConstantRef(
                    constant   = variable.getOwner().getParentModule().\
                                   getFullName(),
                    source_ref = self.getSourceReference()
                )

                change_tags = "new_constant"
                change_desc = """\
Replaced read-only module attribute '__name__' with constant value."""
            elif self.variable_name == "__package__":
                new_node = ExpressionConstantRef(
                    constant=variable.getOwner().getPackage(),
                    source_ref=self.getSourceReference())

                change_tags = "new_constant"
                change_desc = """\
Replaced read-only module attribute '__package__' with constant value."""
            else:
                self.variable_trace.addUsage()

                # Probably should give a warning once about it.
                new_node = self
                change_tags = None
                change_desc = None

            return new_node, change_tags, change_desc

        self.variable_trace.addUsage()

        return self, None, None
Example #16
0
    def computeStatement(self, constraint_collection):
        # Assignment source may re-compute here:
        constraint_collection.onExpression(self.getAssignSource())
        source = self.getAssignSource()

        # No assignment will occur, if the assignment source raises, so strip it
        # away.
        if source.willRaiseException(BaseException):

            result = makeStatementExpressionOnlyReplacementNode(
                expression = source,
                node       = self
            )

            return result, "new_raise", """\
Assignment raises exception in assigned value, removed assignment."""

        variable_ref = self.getTargetVariableRef()
        variable = variable_ref.getVariable()

        # Not allowed anymore at this point.
        assert variable is not None

        # Assigning from and to the same variable, can be optimized away
        # immediately, there is no point in doing it. Exceptions are of course
        # module variables that collide with built-in names.
        if not variable.isModuleVariable() and \
             source.isExpressionVariableRef() and \
             source.getVariable() == variable:

            # A variable access that has a side effect, must be preserved,
            # so it can e.g. raise an exception, otherwise we can be fully
            # removed.
            if source.mayHaveSideEffects():
                result = makeStatementExpressionOnlyReplacementNode(
                    expression = source,
                    node       = self
                )

                return result, "new_statements", """\
Reduced assignment of variable from itself to access of it."""
            else:
                return None, "new_statements", """\
Removed assignment of variable from itself which is known to be defined."""


        # If the assignment source has side effects, we can simply evaluate them
        # beforehand, we have already visited and evaluated them before.
        if source.isExpressionSideEffects():
            statements = [
                makeStatementExpressionOnlyReplacementNode(
                    side_effect,
                    self
                )
                for side_effect in
                source.getSideEffects()
            ]

            statements.append(self)

            parent = self.parent
            result = makeStatementsSequenceReplacementNode(
                statements = statements,
                node       = self,
            )
            result.parent = parent

            # Need to update it.
            self.setAssignSource(source.getExpression())
            source = self.getAssignSource()

            result = result, "new_statements", """\
Side effects of assignments promoted to statements."""
        else:
            result = self, None, None

        # Set-up the trace to the trace collection, so future references will
        # find this assignment.
        self.variable_trace = constraint_collection.onVariableSet(
            assign_node = self
        )

        global_trace = VariableRegistry.getGlobalVariableTrace(variable)

        if global_trace is not None:
            if variable.isTempVariable():
                if source.isCompileTimeConstant() and not source.isMutable():
                    self.variable_trace.setReplacementNode(source)
            elif variable.isLocalVariable():
                if source.isCompileTimeConstant() and not source.isMutable():
                    provider = self.getParentVariableProvider()

                    if provider.isPythonModule() or \
                       (not provider.isUnoptimized() and not provider.isClassDictCreation()):
                        self.variable_trace.setReplacementNode(source)

        return result
Example #17
0
def optimize():
    # This is somewhat complex with many cases, pylint: disable=R0912

    # We maintain this globally to make it accessible, pylint: disable=W0603
    global graph

    if Options.shouldCreateGraph():

        try:
            from graphviz import Digraph  # pylint: disable=F0401,I0021
            graph = Digraph('G')
        except ImportError:
            warning("Cannot import graphviz module, no graphing capability.")

    while True:
        finished = True

        ModuleRegistry.startTraversal()

        while True:
            current_module = ModuleRegistry.nextModule()

            if current_module is None:
                break

            if _progress:
                printLine("""\
Optimizing module '{module_name}', {remaining:d} more modules to go \
after that. Memory usage {memory}:""".format(
                    module_name=current_module.getFullName(),
                    remaining=ModuleRegistry.remainingCount(),
                    memory=Utils.getHumanReadableProcessMemoryUsage()))

            if current_module.isPythonShlibModule():
                optimizeShlibModule(current_module)
            else:
                changed = optimizePythonModule(current_module)

                if changed:
                    finished = False

        # Unregister collection traces from now unused code.
        for current_module in ModuleRegistry.getDoneModules():
            if not current_module.isPythonShlibModule():
                for function in current_module.getUnusedFunctions():
                    VariableRegistry.updateFromCollection(
                        old_collection=function.constraint_collection,
                        new_collection=None)

                    function.constraint_collection = None

        if not VariableRegistry.complete:
            VariableRegistry.complete = True

            finished = False

        for current_module in ModuleRegistry.getDoneModules():
            if not current_module.isPythonShlibModule():
                optimizeVariables(current_module)

        if finished:
            break

    if graph is not None:
        graph.engine = "dot"
        graph.graph_attr["rankdir"] = "TB"
        graph.render("something.dot")

        printLine(graph.source)
Example #18
0
    def computeExpression(self, constraint_collection):
        variable = self.variable

        assert variable is not None

        self.variable_trace = constraint_collection.getVariableCurrentTrace(
            variable = variable
        )

        global_trace = VariableRegistry.getGlobalVariableTrace(variable)

        # TODO: Maybe local variables are factored into this strangely.
        if global_trace is None and variable.isModuleVariable():
            constraint_collection.assumeUnclearLocals()
        elif (variable.isModuleVariable() and not global_trace.hasDefiniteWrites() ) or \
             variable.isMaybeLocalVariable():
            if self.variable_name in Builtins.builtin_exception_names:
                from .BuiltinRefNodes import ExpressionBuiltinExceptionRef

                new_node = ExpressionBuiltinExceptionRef(
                    exception_name = self.variable_name,
                    source_ref     = self.getSourceReference()
                )

                change_tags = "new_builtin_ref"
                change_desc = """\
Module variable '%s' found to be built-in exception reference.""" % (
                    self.variable_name
                )
            elif self.variable_name in Builtins.builtin_names and \
                 self.variable_name != "pow":
                from .BuiltinRefNodes import ExpressionBuiltinRef

                new_node = ExpressionBuiltinRef(
                    builtin_name = self.variable_name,
                    source_ref   = self.getSourceReference()
                )

                change_tags = "new_builtin_ref"
                change_desc = """\
Module variable '%s' found to be built-in reference.""" % (
                    self.variable_name
                )
            elif self.variable_name == "__name__":
                new_node = ExpressionConstantRef(
                    constant   = variable.getOwner().getParentModule().\
                                   getFullName(),
                    source_ref = self.getSourceReference()
                )

                change_tags = "new_constant"
                change_desc = """\
Replaced read-only module attribute '__name__' with constant value."""
            elif self.variable_name == "__package__":
                new_node = ExpressionConstantRef(
                    constant   = variable.getOwner().getPackage(),
                    source_ref = self.getSourceReference()
                )

                change_tags = "new_constant"
                change_desc = """\
Replaced read-only module attribute '__package__' with constant value."""
            else:
                # Probably should give a warning once about it.
                new_node = self
                change_tags = None
                change_desc = None

            return new_node, change_tags, change_desc

        return self, None, None