Skip to content

Commit

Permalink
Optimization: Use common code for global variable accesses
Browse files Browse the repository at this point in the history
* This uses common code to provide the builtins fallback to avoid
  the very verbose code per module variable access.

* Also the exception is created by the common code, and needs not
  be done for each unclear usage.
  • Loading branch information
kayhayen committed Sep 19, 2020
1 parent 55d5549 commit 4369024
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 33 deletions.
5 changes: 5 additions & 0 deletions nuitka/build/include/nuitka/helper/attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,9 @@ extern PyObject *LOOKUP_SPECIAL(PyObject *source, PyObject *attr_name);
extern PyObject *FIND_ATTRIBUTE_IN_CLASS(PyClassObject *klass, PyObject *attr_name);
#endif

extern PyObject *LOOKUP_MODULE_VALUE(PyDictObject *module_dict, PyObject *var_name);
extern PyObject *GET_MODULE_VARIABLE_VALUE(PyDictObject *module_dict, PyObject *variable_name);
#if PYTHON_VERSION < 340
extern PyObject *GET_MODULE_VARIABLE_VALUE_IN_FUNCTION(PyDictObject *module_dict, PyObject *variable_name);
#endif
#endif
56 changes: 56 additions & 0 deletions nuitka/build/static_src/HelpersAttributes.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,3 +730,59 @@ PyObject *LOOKUP_SPECIAL(PyObject *source, PyObject *attr_name) {
SET_CURRENT_EXCEPTION_TYPE0_VALUE0(PyExc_AttributeError, attr_name);
return NULL;
}

PyObject *LOOKUP_MODULE_VALUE(PyDictObject *module_dict, PyObject *var_name) {
PyObject *result = GET_STRING_DICT_VALUE(module_dict, (Nuitka_StringObject *)var_name);

if (unlikely(result == NULL)) {
result = GET_STRING_DICT_VALUE(dict_builtin, (Nuitka_StringObject *)var_name);
}

return result;
}

PyObject *GET_MODULE_VARIABLE_VALUE(PyDictObject *module_dict, PyObject *variable_name) {
PyObject *result = GET_STRING_DICT_VALUE(module_dict, (Nuitka_StringObject *)variable_name);

if (unlikely(result == NULL)) {
result = GET_STRING_DICT_VALUE(dict_builtin, (Nuitka_StringObject *)variable_name);

if (unlikely(result == NULL)) {
PyObject *exception_type;
PyObject *exception_value;

// TODO: Do this in one go, once FORMAT_NAME_ERROR becomes unused in code generation.
FORMAT_NAME_ERROR(&exception_type, &exception_value, variable_name);

#if PYTHON_VERSION >= 300
// TODO: FORMAT_NAME_ERROR for Python3 should already produce this normalized and chained.
NORMALIZE_EXCEPTION(&exception_type, &exception_value, NULL);
CHAIN_EXCEPTION(exception_value);
#endif

RESTORE_ERROR_OCCURRED(exception_type, exception_value, NULL);
}
}

return result;
}

#if PYTHON_VERSION < 340
PyObject *GET_MODULE_VARIABLE_VALUE_IN_FUNCTION(PyDictObject *module_dict, PyObject *variable_name) {
PyObject *result = GET_STRING_DICT_VALUE(module_dict, (Nuitka_StringObject *)variable_name);

if (unlikely(result == NULL)) {
result = GET_STRING_DICT_VALUE(dict_builtin, (Nuitka_StringObject *)variable_name);

if (unlikely(result == NULL)) {
PyObject *exception_type;
PyObject *exception_value;

FORMAT_GLOBAL_NAME_ERROR(&exception_type, &exception_value, variable_name);
RESTORE_ERROR_OCCURRED(exception_type, exception_value, NULL);
}
}

return result;
}
#endif
33 changes: 33 additions & 0 deletions nuitka/codegen/CodeHelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,41 @@ def decideConversionCheckNeeded(to_name, expression):
return conversion_check


# TODO: Get rid of the duplication of code with
# "withObjectCodeTemporaryAssignment" by setting on one of them.


@contextmanager
def withObjectCodeTemporaryAssignment2(
to_name, value_name, needs_conversion_check, emit, context
):
""" Converting to the target type, provide temporary object value name only if necessary. """

if to_name.c_type == "PyObject *":
value_name = to_name
else:
value_name = context.allocateTempName(value_name)

yield value_name

if to_name is not value_name:
to_name.getCType().emitAssignConversionCode(
to_name=to_name,
value_name=value_name,
needs_check=needs_conversion_check,
emit=emit,
context=context,
)

from .ErrorCodes import getReleaseCode

getReleaseCode(value_name, emit, context)


@contextmanager
def withObjectCodeTemporaryAssignment(to_name, value_name, expression, emit, context):
""" Converting to the target type, provide temporary object value name only if necessary. """

if to_name.c_type == "PyObject *":
value_name = to_name
else:
Expand Down
1 change: 1 addition & 0 deletions nuitka/codegen/ErrorCodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ def getLocalVariableReferenceErrorCode(variable, condition, emit, context):
)


# TODO: Get rid of this function entirely.
def getNameReferenceErrorCode(variable_name, condition, emit, context):
helper_code = "FORMAT_NAME_ERROR"

Expand Down
81 changes: 53 additions & 28 deletions nuitka/codegen/VariableCodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,22 @@
tshape_bool,
tshape_int_or_long,
)
from nuitka.PythonVersions import python_version

from .c_types.CTypeNuitkaBools import CTypeNuitkaBoolEnum
from .c_types.CTypePyObjectPtrs import (
CTypeCellObject,
CTypePyObjectPtr,
CTypePyObjectPtrPtr,
)
from .CodeHelpers import decideConversionCheckNeeded, generateExpressionCode
from .CodeHelpers import (
decideConversionCheckNeeded,
generateExpressionCode,
withObjectCodeTemporaryAssignment2,
)
from .ErrorCodes import (
getAssertionCode,
getErrorExitCode,
getLocalVariableReferenceErrorCode,
getNameReferenceErrorCode,
)
Expand Down Expand Up @@ -107,44 +113,63 @@ def getVariableReferenceCode(
to_name, variable, variable_trace, needs_check, conversion_check, emit, context
):
if variable.isModuleVariable():
variable_declaration = VariableDeclaration(
"module_var", variable.getName(), None, None
)
owner = context.getOwner()

with withObjectCodeTemporaryAssignment2(
to_name, "mvar_value", conversion_check, emit, context
) as value_name:
# TODO: Rather have this passed from a distinct node type, so inlining
# doesn't change things.

emit(
"%(value_name)s = %(helper_code)s(moduledict_%(module_identifier)s, %(var_name)s);"
% {
"helper_code": "GET_MODULE_VARIABLE_VALUE_IN_FUNCTION"
if python_version < 340
and not owner.isCompiledPythonModule()
and not owner.isExpressionClassBody()
else "GET_MODULE_VARIABLE_VALUE",
"module_identifier": context.getModuleCodeName(),
"value_name": value_name,
"var_name": context.getConstantCode(constant=variable.getName()),
}
)

getErrorExitCode(
check_name=value_name,
emit=emit,
context=context,
needs_check=needs_check,
)
else:
variable_declaration = getLocalVariableDeclaration(
context, variable, variable_trace
)

value_name = variable_declaration.getCType().emitValueAccessCode(
value_name=variable_declaration, emit=emit, context=context
)

if needs_check:
condition = value_name.getCType().getLocalVariableInitTestCode(value_name, True)
value_name = variable_declaration.getCType().emitValueAccessCode(
value_name=variable_declaration, emit=emit, context=context
)

if variable.isModuleVariable():
getNameReferenceErrorCode(
variable_name=variable.getName(),
condition=condition,
emit=emit,
context=context,
if needs_check:
condition = value_name.getCType().getLocalVariableInitTestCode(
value_name, True
)
else:

getLocalVariableReferenceErrorCode(
variable=variable, condition=condition, emit=emit, context=context
)
else:
value_name.getCType().emitValueAssertionCode(
value_name=value_name, emit=emit, context=context
)
else:
value_name.getCType().emitValueAssertionCode(
value_name=value_name, emit=emit, context=context
)

to_name.getCType().emitAssignConversionCode(
to_name=to_name,
value_name=value_name,
needs_check=conversion_check,
emit=emit,
context=context,
)
to_name.getCType().emitAssignConversionCode(
to_name=to_name,
value_name=value_name,
needs_check=conversion_check,
emit=emit,
context=context,
)


def generateVariableReferenceCode(to_name, expression, emit, context):
Expand Down
6 changes: 1 addition & 5 deletions nuitka/codegen/templates/CodeTemplatesVariables.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,7 @@
# by keeping track of things that were added by "site.py" mechanisms. Then
# we can avoid the second call entirely for most cases.
template_read_mvar_unclear = """\
%(tmp_name)s = GET_STRING_DICT_VALUE(moduledict_%(module_identifier)s, (Nuitka_StringObject *)%(var_name)s);
if (unlikely(%(tmp_name)s == NULL)) {
%(tmp_name)s = GET_STRING_DICT_VALUE(dict_builtin, (Nuitka_StringObject *)%(var_name)s);
}
%(tmp_name)s = LOOKUP_MODULE_VALUE(moduledict_%(module_identifier)s, %(var_name)s);
"""

template_read_locals_dict_with_fallback = """\
Expand Down

0 comments on commit 4369024

Please sign in to comment.