mirror of
https://github.com/Nuitka/Nuitka.git
synced 2025-12-14 20:35:49 +01:00
Optimization: Faster variable trace maintenance
* We now trace variables in trace collection as a dictionary per variable with a dictionary of the versions, this is closer to out frequent usage per variable. * That makes it a lot easier to update variables after the tracing is finished to know their users and writers. * Requires a lot less work, but also makes work less memory local such that the performance gain is relatively small despite less work being done. * Also avoids that a set for the users is to be maintained.
This commit is contained in:
@@ -156,7 +156,7 @@ class SourceCodeReferenceInternal(SourceCodeReference):
|
||||
return True
|
||||
|
||||
|
||||
def fromFilename(filename):
|
||||
def makeSourceReferenceFromFilename(filename):
|
||||
return SourceCodeReference.fromFilenameAndLine(filename=filename, line=1)
|
||||
|
||||
|
||||
|
||||
@@ -51,11 +51,10 @@ class Variable(getMetaClassBase("Variable", require_slots=True)):
|
||||
|
||||
self.shared_users = False
|
||||
|
||||
self.traces = set()
|
||||
self.traces = {}
|
||||
|
||||
# Derived from all traces.
|
||||
self.users = None
|
||||
self.writers = None
|
||||
self.writers = set()
|
||||
|
||||
if isCountingInstances():
|
||||
__del__ = counted_del()
|
||||
@@ -145,12 +144,12 @@ class Variable(getMetaClassBase("Variable", require_slots=True)):
|
||||
if not self.shared_users:
|
||||
return False
|
||||
|
||||
if not self.users:
|
||||
if not self.traces:
|
||||
return False
|
||||
|
||||
owner = self.owner.getEntryPoint()
|
||||
|
||||
for user in self.users:
|
||||
for user in self.traces:
|
||||
user = user.getEntryPoint()
|
||||
|
||||
while user is not owner and (
|
||||
@@ -164,58 +163,65 @@ class Variable(getMetaClassBase("Variable", require_slots=True)):
|
||||
|
||||
return False
|
||||
|
||||
def addTrace(self, variable_trace):
|
||||
self.traces.add(variable_trace)
|
||||
def setTracesForUserFirst(self, user, variable_traces):
|
||||
self.traces[user] = variable_traces
|
||||
|
||||
def removeTrace(self, variable_trace):
|
||||
self.traces.remove(variable_trace)
|
||||
for trace in variable_traces.values():
|
||||
if trace.isAssignTrace():
|
||||
self.writers.add(user)
|
||||
|
||||
def getTraces(self):
|
||||
"""For debugging only"""
|
||||
return self.traces
|
||||
break
|
||||
if user is not self.owner and trace.isDeletedTrace():
|
||||
self.writers.add(user)
|
||||
|
||||
def hasEmptyTracesFor(self, owner):
|
||||
break
|
||||
|
||||
def setTracesForUserUpdate(self, user, variable_traces):
|
||||
self.traces[user] = variable_traces
|
||||
|
||||
if user in self.writers:
|
||||
for trace in variable_traces.values():
|
||||
if trace.isAssignTrace():
|
||||
break
|
||||
if user is not self.owner and trace.isDeletedTrace():
|
||||
break
|
||||
else:
|
||||
self.writers.remove(user)
|
||||
|
||||
def removeTracesForUser(self, user):
|
||||
del self.traces[user]
|
||||
|
||||
if user in self.writers:
|
||||
self.writers.remove(user)
|
||||
|
||||
def hasEmptyTracesFor(self, user):
|
||||
"""Do these traces contain any usage."""
|
||||
for trace in self.traces:
|
||||
if trace.owner is owner and trace.isUsingTrace():
|
||||
return False
|
||||
if user in self.traces:
|
||||
for trace in self.traces[user].values():
|
||||
if trace.isUsingTrace():
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def hasNoWritingTraces(self):
|
||||
"""Do these traces contain any writes."""
|
||||
|
||||
for trace in self.traces:
|
||||
if trace.isWritingTrace():
|
||||
return False
|
||||
for traces in self.traces.values():
|
||||
for trace in traces.values():
|
||||
if trace.isWritingTrace():
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def updateUsageState(self):
|
||||
writers = set()
|
||||
users = set()
|
||||
|
||||
for trace in self.traces:
|
||||
owner = trace.owner
|
||||
users.add(owner)
|
||||
|
||||
if trace.isAssignTrace():
|
||||
writers.add(owner)
|
||||
elif owner is not self.owner and trace.isDeletedTrace():
|
||||
writers.add(owner)
|
||||
|
||||
self.writers = writers
|
||||
self.users = users
|
||||
|
||||
def hasAccessesOutsideOf(self, provider):
|
||||
if not self.owner.locals_scope.complete:
|
||||
return None
|
||||
elif self.users is None:
|
||||
elif not self.traces:
|
||||
return False
|
||||
elif provider in self.users:
|
||||
return len(self.users) > 1
|
||||
elif provider in self.traces:
|
||||
return len(self.traces) > 1
|
||||
else:
|
||||
return bool(self.users)
|
||||
return True
|
||||
|
||||
def hasWritersOutsideOf(self, provider):
|
||||
if not self.owner.locals_scope.complete:
|
||||
@@ -225,45 +231,50 @@ class Variable(getMetaClassBase("Variable", require_slots=True)):
|
||||
):
|
||||
return False
|
||||
return None
|
||||
elif self.writers is None:
|
||||
elif not self.writers:
|
||||
return False
|
||||
elif provider in self.writers:
|
||||
return len(self.writers) > 1
|
||||
else:
|
||||
return bool(self.writers)
|
||||
return True
|
||||
|
||||
def getMatchingUnescapedAssignTrace(self, assign_node):
|
||||
found = None
|
||||
for trace in self.traces:
|
||||
if trace.isAssignTrace():
|
||||
if trace.getAssignNode() is assign_node:
|
||||
found = trace
|
||||
elif trace.isEscapeTrace():
|
||||
return None
|
||||
for traces in self.traces.values():
|
||||
for trace in traces.values():
|
||||
if trace.isAssignTrace():
|
||||
if trace.getAssignNode() is assign_node:
|
||||
found = trace
|
||||
elif trace.isEscapeTrace():
|
||||
return None
|
||||
|
||||
if found is not None:
|
||||
return found
|
||||
|
||||
return found
|
||||
|
||||
def getTypeShapes(self):
|
||||
result = set()
|
||||
|
||||
for trace in self.traces:
|
||||
if trace.isAssignTrace():
|
||||
result.add(trace.getAssignNode().getTypeShape())
|
||||
elif trace.isUnknownTrace():
|
||||
result.add(tshape_unknown)
|
||||
elif trace.isEscapeTrace():
|
||||
result.add(tshape_unknown)
|
||||
elif trace.isInitTrace():
|
||||
result.add(tshape_unknown)
|
||||
elif trace.isUnassignedTrace():
|
||||
pass
|
||||
elif trace.isMergeTrace():
|
||||
pass
|
||||
# TODO: Remove this and be not unknown.
|
||||
elif trace.isLoopTrace():
|
||||
trace.getTypeShape().emitAlternatives(result.add)
|
||||
else:
|
||||
assert False, trace
|
||||
for traces in self.traces.values():
|
||||
for trace in traces.values():
|
||||
if trace.isAssignTrace():
|
||||
result.add(trace.getAssignNode().getTypeShape())
|
||||
elif trace.isUnknownTrace():
|
||||
result.add(tshape_unknown)
|
||||
elif trace.isEscapeTrace():
|
||||
result.add(tshape_unknown)
|
||||
elif trace.isInitTrace():
|
||||
result.add(tshape_unknown)
|
||||
elif trace.isUnassignedTrace():
|
||||
pass
|
||||
elif trace.isMergeTrace():
|
||||
pass
|
||||
# TODO: Remove this and be not unknown.
|
||||
elif trace.isLoopTrace():
|
||||
trace.getTypeShape().emitAlternatives(result.add)
|
||||
else:
|
||||
assert False, trace
|
||||
|
||||
return result
|
||||
|
||||
@@ -442,49 +453,58 @@ class LocalsDictVariable(Variable):
|
||||
return trace_collection.initVariableUnknown(self)
|
||||
|
||||
|
||||
def _updateVariablesFromCollectionFirst(new_collection):
|
||||
for variable, variable_traces in iterItems(new_collection.getVariableTracesAll()):
|
||||
variable.setTracesForUserFirst(new_collection.owner, variable_traces)
|
||||
|
||||
# Release the memory, and prevent the "active" state from being ever
|
||||
# inspected, it's useless now.
|
||||
new_collection.variable_actives.clear()
|
||||
del new_collection.variable_actives
|
||||
|
||||
|
||||
def updateVariablesFromCollection(old_collection, new_collection, source_ref):
|
||||
# After removing/adding traces, we need to pre-compute the users state
|
||||
# information.
|
||||
touched_variables = set()
|
||||
loop_trace_removal = set()
|
||||
|
||||
if old_collection is None:
|
||||
return _updateVariablesFromCollectionFirst(new_collection)
|
||||
|
||||
old_traces = old_collection.getVariableTracesAll()
|
||||
new_traces = new_collection.getVariableTracesAll()
|
||||
owner = new_collection.owner
|
||||
# Release the memory, and prevent the "active" state from being ever
|
||||
# inspected, it's useless now.
|
||||
new_collection.variable_actives.clear()
|
||||
del new_collection.variable_actives
|
||||
|
||||
for variable, variable_traces in iterItems(new_traces):
|
||||
variable.setTracesForUserUpdate(owner, variable_traces)
|
||||
|
||||
for variable in old_traces:
|
||||
if variable not in new_traces:
|
||||
variable.removeTracesForUser(owner)
|
||||
|
||||
if old_collection.loop_variables != new_collection.loop_variables:
|
||||
new_collection.signalChange(
|
||||
"var_usage",
|
||||
source_ref,
|
||||
lambda: "Loop variable '%s' usage ceased."
|
||||
% ",".join(
|
||||
sorted(
|
||||
variable.getName()
|
||||
for variable in (
|
||||
old_collection.loop_variables - new_collection.loop_variables
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def removeVariablesFromCollection(old_collection):
|
||||
if old_collection is not None:
|
||||
for (variable, _version), variable_trace in iterItems(
|
||||
old_collection.getVariableTracesAll()
|
||||
):
|
||||
variable.removeTrace(variable_trace)
|
||||
touched_variables.add(variable)
|
||||
owner = old_collection.owner
|
||||
|
||||
if variable_trace.isLoopTrace():
|
||||
loop_trace_removal.add(variable)
|
||||
|
||||
if new_collection is not None:
|
||||
for (variable, _version), variable_trace in iterItems(
|
||||
new_collection.getVariableTracesAll()
|
||||
):
|
||||
variable.addTrace(variable_trace)
|
||||
touched_variables.add(variable)
|
||||
|
||||
if variable_trace.isLoopTrace():
|
||||
if variable in loop_trace_removal:
|
||||
loop_trace_removal.remove(variable)
|
||||
|
||||
# Release the memory, and prevent the "active" state from being ever
|
||||
# inspected, it's useless now.
|
||||
new_collection.variable_actives.clear()
|
||||
del new_collection.variable_actives
|
||||
|
||||
for variable in touched_variables:
|
||||
variable.updateUsageState()
|
||||
|
||||
if loop_trace_removal:
|
||||
if new_collection is not None:
|
||||
new_collection.signalChange(
|
||||
"var_usage",
|
||||
source_ref,
|
||||
lambda: "Loop variable '%s' usage ceased."
|
||||
% ",".join(variable.getName() for variable in loop_trace_removal),
|
||||
)
|
||||
for variable in old_collection.getVariableTracesAll():
|
||||
variable.removeTracesForUser(owner)
|
||||
|
||||
|
||||
# To detect the Python2 shared variable deletion, that would be a syntax
|
||||
|
||||
@@ -34,6 +34,7 @@ from nuitka.Errors import NuitkaCodeDeficit
|
||||
from nuitka.plugins.Plugins import Plugins
|
||||
from nuitka.PythonFlavors import isNuitkaPython
|
||||
from nuitka.PythonVersions import python_version
|
||||
from nuitka.SourceCodeReferences import makeSourceReferenceFromFilename
|
||||
from nuitka.Tracing import recursion_logger
|
||||
from nuitka.tree.ReformulationMultidist import locateMultidistModule
|
||||
from nuitka.utils.AppDirs import getCacheDir
|
||||
@@ -1079,14 +1080,14 @@ def decideModuleSourceRef(filename, module_name, is_main, is_fake, logger):
|
||||
if is_fake:
|
||||
source_filename = filename
|
||||
|
||||
source_ref = SourceCodeReferences.fromFilename(filename=filename)
|
||||
source_ref = makeSourceReferenceFromFilename(filename=filename)
|
||||
|
||||
module_name = is_fake
|
||||
|
||||
elif os.path.isfile(filename):
|
||||
source_filename = filename
|
||||
|
||||
source_ref = SourceCodeReferences.fromFilename(filename=filename)
|
||||
source_ref = makeSourceReferenceFromFilename(filename=filename)
|
||||
|
||||
elif isPackageDir(filename):
|
||||
is_package = True
|
||||
@@ -1094,12 +1095,10 @@ def decideModuleSourceRef(filename, module_name, is_main, is_fake, logger):
|
||||
source_filename = getNormalizedPath(os.path.join(filename, "__init__.py"))
|
||||
|
||||
if not os.path.isfile(source_filename):
|
||||
source_ref = SourceCodeReferences.fromFilename(
|
||||
filename=filename
|
||||
).atInternal()
|
||||
source_ref = makeSourceReferenceFromFilename(filename=filename).atInternal()
|
||||
is_namespace = True
|
||||
else:
|
||||
source_ref = SourceCodeReferences.fromFilename(
|
||||
source_ref = makeSourceReferenceFromFilename(
|
||||
filename=getNormalizedPath(os.path.abspath(source_filename))
|
||||
)
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ classes.
|
||||
import inspect
|
||||
import re
|
||||
|
||||
from nuitka import Options, Variables
|
||||
from nuitka import Options
|
||||
from nuitka.Constants import isMutable
|
||||
from nuitka.optimizations.TraceCollections import (
|
||||
TraceCollectionPureFunction,
|
||||
@@ -35,6 +35,7 @@ from nuitka.tree.Extractions import updateVariableUsage
|
||||
from nuitka.tree.SourceHandling import readSourceLines
|
||||
from nuitka.tree.TreeHelpers import makeDictCreationOrConstant2
|
||||
from nuitka.utils.CStrings import decodePythonIdentifierFromC
|
||||
from nuitka.Variables import LocalVariable, updateVariablesFromCollection
|
||||
|
||||
from .ChildrenHavingMixins import (
|
||||
ChildHavingBodyOptionalMixin,
|
||||
@@ -234,13 +235,9 @@ class ExpressionFunctionBodyBase(
|
||||
|
||||
assert variable.getOwner() is not self
|
||||
|
||||
new_variable = Variables.LocalVariable(
|
||||
owner=self, variable_name=variable.getName()
|
||||
)
|
||||
for variable_trace in variable.traces:
|
||||
if variable_trace.getOwner() is self:
|
||||
new_variable.addTrace(variable_trace)
|
||||
new_variable.updateUsageState()
|
||||
new_variable = LocalVariable(owner=self, variable_name=variable.getName())
|
||||
if self in variable.traces:
|
||||
new_variable.setTracesForUserFirst(self, variable.traces[self])
|
||||
|
||||
self.locals_scope.unregisterClosureVariable(variable)
|
||||
self.locals_scope.registerProvidedVariable(new_variable)
|
||||
@@ -489,7 +486,7 @@ class ExpressionFunctionEntryPointBase(EntryPointMixin, ExpressionFunctionBodyBa
|
||||
|
||||
self.computeFunction(trace_collection)
|
||||
|
||||
trace_collection.updateVariablesFromCollection(old_collection, self.source_ref)
|
||||
updateVariablesFromCollection(old_collection, trace_collection, self.source_ref)
|
||||
|
||||
def computeFunction(self, trace_collection):
|
||||
statements_sequence = self.subnode_body
|
||||
@@ -838,8 +835,8 @@ class ExpressionFunctionPureBody(ExpressionFunctionBody):
|
||||
with withChangeIndicationsTo(mySignal):
|
||||
self.computeFunction(trace_collection)
|
||||
|
||||
trace_collection.updateVariablesFromCollection(
|
||||
old_collection, self.source_ref
|
||||
updateVariablesFromCollection(
|
||||
old_collection, trace_collection, self.source_ref
|
||||
)
|
||||
|
||||
if tags:
|
||||
|
||||
@@ -9,15 +9,19 @@ together and cross-module optimizations are the most difficult to tackle.
|
||||
|
||||
import os
|
||||
|
||||
from nuitka import Options, Variables
|
||||
from nuitka.containers.OrderedSets import OrderedSet
|
||||
from nuitka.importing.Importing import locateModule, makeModuleUsageAttempt
|
||||
from nuitka.importing.Recursion import decideRecursion, recurseTo
|
||||
from nuitka.ModuleRegistry import getModuleByName, getOwnerFromCodeName
|
||||
from nuitka.optimizations.TraceCollections import TraceCollectionModule
|
||||
from nuitka.Options import hasPythonFlagIsolated
|
||||
from nuitka.Options import (
|
||||
getFileReferenceMode,
|
||||
hasPythonFlagIsolated,
|
||||
hasPythonFlagPackageMode,
|
||||
shallMakeModule,
|
||||
)
|
||||
from nuitka.PythonVersions import python_version
|
||||
from nuitka.SourceCodeReferences import fromFilename
|
||||
from nuitka.SourceCodeReferences import makeSourceReferenceFromFilename
|
||||
from nuitka.tree.SourceHandling import parsePyIFile, readSourceCodeFromFilename
|
||||
from nuitka.utils.CStrings import encodePythonIdentifierToC
|
||||
from nuitka.utils.FileOperations import switchFilenameExtension
|
||||
@@ -26,6 +30,7 @@ from nuitka.utils.Importing import (
|
||||
getPackageDirFilename,
|
||||
)
|
||||
from nuitka.utils.ModuleNames import ModuleName
|
||||
from nuitka.Variables import ModuleVariable, updateVariablesFromCollection
|
||||
|
||||
from .ChildrenHavingMixins import (
|
||||
ModuleChildrenHavingBodyOptionalStatementsOrNoneFunctionsTupleMixin,
|
||||
@@ -174,7 +179,7 @@ class PythonModuleBase(NodeBase):
|
||||
return result
|
||||
|
||||
def getRunTimeFilename(self):
|
||||
reference_mode = Options.getFileReferenceMode()
|
||||
reference_mode = getFileReferenceMode()
|
||||
|
||||
if reference_mode == "original":
|
||||
return self.getCompileTimeFilename()
|
||||
@@ -442,7 +447,7 @@ class CompiledPythonModule(
|
||||
def createProvidedVariable(self, variable_name):
|
||||
assert variable_name not in self.variables
|
||||
|
||||
result = Variables.ModuleVariable(module=self, variable_name=variable_name)
|
||||
result = ModuleVariable(module=self, variable_name=variable_name)
|
||||
|
||||
self.variables[variable_name] = result
|
||||
|
||||
@@ -604,8 +609,8 @@ class CompiledPythonModule(
|
||||
)
|
||||
|
||||
# Finalize locals scopes previously determined for removal in last pass.
|
||||
self.trace_collection.updateVariablesFromCollection(
|
||||
old_collection=old_collection, source_ref=self.source_ref
|
||||
updateVariablesFromCollection(
|
||||
old_collection, self.trace_collection, self.source_ref
|
||||
)
|
||||
|
||||
# Indicate if this is pass 1 for the module as return value.
|
||||
@@ -711,7 +716,7 @@ class CompiledPythonModule(
|
||||
return None
|
||||
|
||||
def getRuntimeNameValue(self):
|
||||
if self.isMainModule() and Options.hasPythonFlagPackageMode():
|
||||
if self.isMainModule() and hasPythonFlagPackageMode():
|
||||
return "__main__"
|
||||
elif self.module_name.isMultidistModuleName():
|
||||
return "__main__"
|
||||
@@ -766,7 +771,7 @@ class CompiledPythonNamespacePackage(CompiledPythonPackage):
|
||||
def makeUncompiledPythonModule(
|
||||
module_name, reason, filename, bytecode, is_package, technical
|
||||
):
|
||||
source_ref = fromFilename(filename)
|
||||
source_ref = makeSourceReferenceFromFilename(filename)
|
||||
|
||||
if is_package:
|
||||
return UncompiledPythonPackage(
|
||||
@@ -872,7 +877,7 @@ class PythonMainModule(CompiledPythonModule):
|
||||
__slots__ = ("main_added", "standard_library_modules")
|
||||
|
||||
def __init__(self, module_name, main_added, mode, future_spec, source_ref):
|
||||
assert not Options.shallMakeModule()
|
||||
assert not shallMakeModule()
|
||||
|
||||
# Is this one from a "__main__.py" file
|
||||
self.main_added = main_added
|
||||
|
||||
@@ -13,7 +13,6 @@ import contextlib
|
||||
from collections import defaultdict
|
||||
from contextlib import contextmanager
|
||||
|
||||
from nuitka import Variables
|
||||
from nuitka.__past__ import iterItems # Python3 compatibility.
|
||||
from nuitka.containers.OrderedDicts import OrderedDict
|
||||
from nuitka.containers.OrderedSets import OrderedSet
|
||||
@@ -82,27 +81,15 @@ class CollectionUpdateMixin(object):
|
||||
# Mixins are not allowed to specify slots.
|
||||
__slots__ = ()
|
||||
|
||||
def hasVariableTrace(self, variable, version):
|
||||
return (variable, version) in self.variable_traces
|
||||
|
||||
def getVariableTrace(self, variable, version):
|
||||
return self.variable_traces[(variable, version)]
|
||||
|
||||
def getVariableTracesAll(self):
|
||||
return self.variable_traces
|
||||
|
||||
def addVariableTrace(self, variable, version, trace):
|
||||
key = variable, version
|
||||
|
||||
assert key not in self.variable_traces, (key, self)
|
||||
self.variable_traces[key] = trace
|
||||
|
||||
def addVariableMergeMultipleTrace(self, variable, traces):
|
||||
version = variable.allocateTargetNumber()
|
||||
|
||||
trace_merge = ValueTraceMerge(traces)
|
||||
|
||||
self.addVariableTrace(variable, version, trace_merge)
|
||||
version = variable.allocateTargetNumber()
|
||||
|
||||
self.variable_traces[variable][version] = trace_merge
|
||||
|
||||
return version
|
||||
|
||||
@@ -113,11 +100,11 @@ class CollectionStartPointMixin(CollectionUpdateMixin):
|
||||
These are modules, functions, etc. typically entry points.
|
||||
"""
|
||||
|
||||
# Many things are traced, pylint: disable=too-many-instance-attributes
|
||||
|
||||
# Mixins are not allowed to specify slots, pylint: disable=assigning-non-slot
|
||||
__slots__ = ()
|
||||
|
||||
# Many things are traced
|
||||
|
||||
def __init__(self):
|
||||
# Variable assignments performed in here, last issued number, only used
|
||||
# to determine the next number that should be used for a new assignment.
|
||||
@@ -125,7 +112,7 @@ class CollectionStartPointMixin(CollectionUpdateMixin):
|
||||
|
||||
# The full trace of a variable with a version for the function or module
|
||||
# this is.
|
||||
self.variable_traces = {}
|
||||
self.variable_traces = defaultdict(dict)
|
||||
|
||||
self.break_collections = None
|
||||
self.continue_collections = None
|
||||
@@ -134,6 +121,10 @@ class CollectionStartPointMixin(CollectionUpdateMixin):
|
||||
|
||||
self.outline_functions = None
|
||||
|
||||
# What loop variables were there, them going away is something we want
|
||||
# to know.
|
||||
self.loop_variables = set()
|
||||
|
||||
def getLoopBreakCollections(self):
|
||||
return self.break_collections
|
||||
|
||||
@@ -197,10 +188,6 @@ class CollectionStartPointMixin(CollectionUpdateMixin):
|
||||
def getExceptionRaiseCollections(self):
|
||||
return self.exception_collections
|
||||
|
||||
# TODO: Eliminate this function, call it directly where this is used.
|
||||
def updateVariablesFromCollection(self, old_collection, source_ref):
|
||||
Variables.updateVariablesFromCollection(old_collection, self, source_ref)
|
||||
|
||||
@contextlib.contextmanager
|
||||
def makeAbortStackContext(
|
||||
self, catch_breaks, catch_continues, catch_returns, catch_exceptions
|
||||
@@ -327,7 +314,7 @@ class TraceCollectionBase(object):
|
||||
lazy so to keep the tracing branches minimal where possible.
|
||||
"""
|
||||
|
||||
return self.getVariableTrace(variable, self.variable_actives[variable])
|
||||
return self.variable_traces[variable][self.variable_actives[variable]]
|
||||
|
||||
def hasVariableCurrentTrace(self, variable):
|
||||
return variable in self.variable_actives
|
||||
@@ -359,52 +346,43 @@ class TraceCollectionBase(object):
|
||||
|
||||
def markActiveVariableAsEscaped(self, variable):
|
||||
version = self.variable_actives[variable]
|
||||
current = self.getVariableTrace(variable, version)
|
||||
variable_traces = self.variable_traces[variable]
|
||||
current = variable_traces[version]
|
||||
|
||||
if current.isTraceThatNeedsEscape():
|
||||
# Escape traces are div 3 rem 1.
|
||||
version = version // 3 * 3 + 1
|
||||
|
||||
if not self.hasVariableTrace(variable, version):
|
||||
self.addVariableTrace(
|
||||
variable,
|
||||
version,
|
||||
ValueTraceEscaped(self.owner, current),
|
||||
)
|
||||
if version not in variable_traces:
|
||||
variable_traces[version] = ValueTraceEscaped(self.owner, current)
|
||||
|
||||
self.markCurrentVariableTrace(variable, version)
|
||||
|
||||
def markClosureVariableAsUnknown(self, variable):
|
||||
version = self.variable_actives[variable]
|
||||
current = self.getVariableTrace(variable, version)
|
||||
variable_traces = self.variable_traces[variable]
|
||||
current = variable_traces[version]
|
||||
|
||||
if not current.isUnknownTrace():
|
||||
# Unknown traces are div 3 rem 2.
|
||||
version = version // 3 * 3 + 2
|
||||
|
||||
if not self.hasVariableTrace(variable, version):
|
||||
self.addVariableTrace(
|
||||
variable,
|
||||
version,
|
||||
ValueTraceUnknown(self.owner, current),
|
||||
)
|
||||
if version not in variable_traces:
|
||||
variable_traces[version] = ValueTraceUnknown(self.owner, current)
|
||||
|
||||
self.markCurrentVariableTrace(variable, version)
|
||||
|
||||
def markActiveVariableAsUnknown(self, variable):
|
||||
version = self.variable_actives[variable]
|
||||
current = self.getVariableTrace(variable, version)
|
||||
variable_traces = self.variable_traces[variable]
|
||||
current = variable_traces[version]
|
||||
|
||||
if not current.isUnknownOrVeryTrustedTrace():
|
||||
# Unknown traces are div 3 rem 2.
|
||||
version = version // 3 * 3 + 2
|
||||
|
||||
if not self.hasVariableTrace(variable, version):
|
||||
self.addVariableTrace(
|
||||
variable,
|
||||
version,
|
||||
ValueTraceUnknown(self.owner, current),
|
||||
)
|
||||
if version not in variable_traces:
|
||||
variable_traces[version] = ValueTraceUnknown(self.owner, current)
|
||||
|
||||
self.markCurrentVariableTrace(variable, version)
|
||||
|
||||
@@ -424,7 +402,7 @@ class TraceCollectionBase(object):
|
||||
result = ValueTraceLoopComplete(loop_node, current, shapes)
|
||||
|
||||
version = variable.allocateTargetNumber()
|
||||
self.addVariableTrace(variable, version, result)
|
||||
self.variable_traces[variable][version] = result
|
||||
|
||||
self.markCurrentVariableTrace(variable, version)
|
||||
|
||||
@@ -480,7 +458,7 @@ class TraceCollectionBase(object):
|
||||
self.getVariableCurrentTrace(variable),
|
||||
)
|
||||
|
||||
self.addVariableTrace(variable, version, variable_trace)
|
||||
self.variable_traces[variable][version] = variable_trace
|
||||
|
||||
# Make references point to it.
|
||||
self.markCurrentVariableTrace(variable, version)
|
||||
@@ -514,7 +492,7 @@ class TraceCollectionBase(object):
|
||||
self.getVariableCurrentTrace(variable),
|
||||
)
|
||||
|
||||
self.addVariableTrace(variable, version, variable_trace)
|
||||
self.variable_traces[variable][version] = variable_trace
|
||||
|
||||
# Make references point to it.
|
||||
self.markCurrentVariableTrace(variable, version)
|
||||
@@ -528,7 +506,7 @@ class TraceCollectionBase(object):
|
||||
self.getVariableCurrentTrace(variable),
|
||||
)
|
||||
|
||||
self.addVariableTrace(variable, version, variable_trace)
|
||||
self.variable_traces[variable][version] = variable_trace
|
||||
|
||||
# Make references point to it.
|
||||
self.markCurrentVariableTrace(variable, version)
|
||||
@@ -545,7 +523,7 @@ class TraceCollectionBase(object):
|
||||
replacement,
|
||||
)
|
||||
|
||||
self.addVariableTrace(variable, version, variable_trace)
|
||||
self.variable_traces[variable][version] = variable_trace
|
||||
|
||||
# Make references point to it.
|
||||
self.markCurrentVariableTrace(variable, version)
|
||||
@@ -566,7 +544,7 @@ class TraceCollectionBase(object):
|
||||
)
|
||||
|
||||
# Assign to not initialized again.
|
||||
self.addVariableTrace(variable, version, variable_trace)
|
||||
self.variable_traces[variable][version] = variable_trace
|
||||
|
||||
# Make references point to it.
|
||||
self.markCurrentVariableTrace(variable, version)
|
||||
@@ -765,8 +743,10 @@ class TraceCollectionBase(object):
|
||||
other_version = collection2.variable_actives[variable]
|
||||
|
||||
if version != other_version:
|
||||
trace1 = self.getVariableTrace(variable, version)
|
||||
trace2 = self.getVariableTrace(variable, other_version)
|
||||
variable_traces = self.variable_traces[variable]
|
||||
|
||||
trace1 = variable_traces[version]
|
||||
trace2 = variable_traces[other_version]
|
||||
|
||||
if version % 3 == 1 and trace1.previous is trace2:
|
||||
pass
|
||||
@@ -840,8 +820,10 @@ class TraceCollectionBase(object):
|
||||
escaped = []
|
||||
winner_version = None
|
||||
|
||||
variable_traces = self.variable_traces[variable]
|
||||
|
||||
for version in sorted(versions):
|
||||
trace = self.getVariableTrace(variable, version)
|
||||
trace = variable_traces[version]
|
||||
|
||||
if version % 3 == 1:
|
||||
winner_version = version
|
||||
@@ -872,7 +854,7 @@ class TraceCollectionBase(object):
|
||||
|
||||
# TODO: This could be avoided, if we detect no actual changes being present, but it might
|
||||
# be more costly.
|
||||
self.has_unescaped_variables = False
|
||||
self.has_unescaped_variables = True
|
||||
|
||||
def replaceBranch(self, collection_replace):
|
||||
self.variable_actives = collection_replace.variable_actives
|
||||
@@ -961,48 +943,51 @@ class TraceCollectionBase(object):
|
||||
def initVariableUnknown(self, variable):
|
||||
trace = ValueTraceUnknown(self.owner, None)
|
||||
|
||||
self.addVariableTrace(variable, 0, trace)
|
||||
self.variable_traces[variable][0] = trace
|
||||
|
||||
return trace
|
||||
|
||||
def initVariableModule(self, variable):
|
||||
trace = ValueTraceUnknown(self.owner, None)
|
||||
|
||||
self.addVariableTrace(variable, 0, trace)
|
||||
self.variable_traces[variable][0] = trace
|
||||
|
||||
return trace
|
||||
|
||||
def initVariableInit(self, variable):
|
||||
trace = ValueTraceInit(self.owner)
|
||||
|
||||
self.addVariableTrace(variable, 0, trace)
|
||||
self.variable_traces[variable][0] = trace
|
||||
|
||||
return trace
|
||||
|
||||
def initVariableInitStarArgs(self, variable):
|
||||
trace = ValueTraceInitStarArgs(self.owner)
|
||||
|
||||
self.addVariableTrace(variable, 0, trace)
|
||||
self.variable_traces[variable][0] = trace
|
||||
|
||||
return trace
|
||||
|
||||
def initVariableInitStarDict(self, variable):
|
||||
trace = ValueTraceInitStarDict(self.owner)
|
||||
|
||||
self.addVariableTrace(variable, 0, trace)
|
||||
self.variable_traces[variable][0] = trace
|
||||
|
||||
return trace
|
||||
|
||||
def initVariableUninitialized(self, variable):
|
||||
trace = ValueTraceUninitialized(self.owner, None)
|
||||
|
||||
self.addVariableTrace(variable, 0, trace)
|
||||
self.variable_traces[variable][0] = trace
|
||||
|
||||
return trace
|
||||
|
||||
|
||||
class TraceCollectionBranch(CollectionUpdateMixin, TraceCollectionBase):
|
||||
__slots__ = ("variable_traces",)
|
||||
__slots__ = (
|
||||
"variable_traces",
|
||||
"loop_variables",
|
||||
)
|
||||
|
||||
def __init__(self, name, parent):
|
||||
TraceCollectionBase.__init__(
|
||||
@@ -1021,6 +1006,7 @@ class TraceCollectionBranch(CollectionUpdateMixin, TraceCollectionBase):
|
||||
|
||||
# For quick access without going to parent.
|
||||
self.variable_traces = parent.variable_traces
|
||||
self.loop_variables = parent.loop_variables
|
||||
|
||||
def computeBranch(self, branch):
|
||||
assert branch.isStatementsSequence()
|
||||
@@ -1034,7 +1020,10 @@ class TraceCollectionBranch(CollectionUpdateMixin, TraceCollectionBase):
|
||||
|
||||
|
||||
class TraceCollectionSnapshot(CollectionUpdateMixin, TraceCollectionBase):
|
||||
__slots__ = ("variable_traces",)
|
||||
__slots__ = (
|
||||
"variable_traces",
|
||||
"loop_variables",
|
||||
)
|
||||
|
||||
def __init__(self, name, parent):
|
||||
TraceCollectionBase.__init__(
|
||||
@@ -1053,12 +1042,14 @@ class TraceCollectionSnapshot(CollectionUpdateMixin, TraceCollectionBase):
|
||||
|
||||
# For quick access without going to parent.
|
||||
self.variable_traces = parent.variable_traces
|
||||
self.loop_variables = parent.loop_variables
|
||||
|
||||
|
||||
class TraceCollectionFunction(CollectionStartPointMixin, TraceCollectionBase):
|
||||
__slots__ = (
|
||||
"variable_versions",
|
||||
"variable_traces",
|
||||
"loop_variables",
|
||||
"break_collections",
|
||||
"continue_collections",
|
||||
"return_collections",
|
||||
@@ -1149,7 +1140,7 @@ class TraceCollectionFunction(CollectionStartPointMixin, TraceCollectionBase):
|
||||
None,
|
||||
)
|
||||
|
||||
self.addVariableTrace(variable, 0, assign_trace)
|
||||
self.variable_traces[variable][0] = assign_trace
|
||||
|
||||
return assign_trace
|
||||
|
||||
@@ -1177,6 +1168,7 @@ class TraceCollectionModule(CollectionStartPointMixin, TraceCollectionBase):
|
||||
__slots__ = (
|
||||
"variable_versions",
|
||||
"variable_traces",
|
||||
"loop_variables",
|
||||
"break_collections",
|
||||
"continue_collections",
|
||||
"return_collections",
|
||||
@@ -1248,24 +1240,6 @@ class TraceCollectionModule(CollectionStartPointMixin, TraceCollectionBase):
|
||||
self.distribution_names[distribution_name] = success
|
||||
|
||||
|
||||
def _checkActivesDiff(a1, a2):
|
||||
result = True
|
||||
for variable in a1:
|
||||
if variable not in a2:
|
||||
print("Only in a1", variable)
|
||||
result = False
|
||||
elif a1[variable] != a2[variable]:
|
||||
print("Different ", variable, a1[variable], a2[variable])
|
||||
result = False
|
||||
|
||||
for variable in a2:
|
||||
if variable not in a1:
|
||||
print("Only in a2", variable)
|
||||
result = False
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# Part of "Nuitka", an optimizing Python compiler that is compatible and
|
||||
# integrates with CPython, but also works on its own.
|
||||
#
|
||||
|
||||
@@ -16,9 +16,9 @@ from nuitka.nodes.FunctionNodes import (
|
||||
ExpressionFunctionPureBody,
|
||||
ExpressionFunctionPureInlineConstBody,
|
||||
)
|
||||
from nuitka.SourceCodeReferences import fromFilename
|
||||
from nuitka.SourceCodeReferences import makeSourceReferenceFromFilename
|
||||
|
||||
internal_source_ref = fromFilename("internal").atInternal()
|
||||
internal_source_ref = makeSourceReferenceFromFilename("internal").atInternal()
|
||||
|
||||
|
||||
def once_decorator(func):
|
||||
|
||||
Reference in New Issue
Block a user