def analyse_target_types(self, env):
self.analyse_types(env)
+ def gil_check(self, env):
+ # By default, any expression based on Python objects is
+ # prevented in nogil environments. Subtypes must override
+ # this if they can work without the GIL.
+ if self.type.is_pyobject:
+ self._gil_check(env)
+
def gil_assignment_check(self, env):
if env.nogil and self.type.is_pyobject:
error(self.pos, "Assignment of Python object not allowed without gil")
def addr_not_const(self):
error(self.pos, "Address is not constant")
- def gil_check(self, env):
- if env is not None and env.nogil and self.type.is_pyobject:
- self.gil_error()
-
# ----------------- Result Allocation -----------------
def result_in_temp(self):
value = "Py_None"
constant_result = None
+ gil_check = None
def compile_time_value(self, denv):
return None
# value string C code fragment
is_literal = 1
-
+ gil_check = None
+
def is_simple(self):
return 1
def calculate_result_code(self):
return str(int(self.value))
+
class NullNode(ConstNode):
type = PyrexTypes.c_null_ptr_type
value = "NULL"
def compile_time_value(self, denv):
return long(self.value)
-
- gil_message = "Constructing Python long int"
def analyse_types(self, env):
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing Python long int"
def analyse_types(self, env):
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing complex number"
is_cython_module = False
cython_attribute = None
lhs_of_first_assignment = False
+ is_used_as_rvalue = 0
entry = None
def create_analysed_rvalue(pos, env, entry):
self.is_temp = 0
else:
self.is_temp = 1
+ self.is_used_as_rvalue = 1
env.use_utility_code(get_name_interned_utility_code)
- self.gil_check(env)
+
+ def gil_check(self, env):
+ if self.is_used_as_rvalue:
+ entry = self.entry
+ if entry.is_builtin:
+ # if not Options.cache_builtins: # cached builtins are ok
+ self._gil_check(env)
+ elif entry.is_pyglobal:
+ self._gil_check(env)
gil_message = "Accessing Python global or builtin"
self.arg.analyse_types(env)
self.arg = self.arg.coerce_to_pyobject(env)
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
gil_message = "Backquote expression"
self.name_list.analyse_types(env)
self.name_list.coerce_to_pyobject(env)
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
env.use_utility_code(import_utility_code)
self.sequence.analyse_types(env)
self.sequence = self.sequence.coerce_to_pyobject(env)
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
gil_message = "Iterating over Python object"
else:
self.index = self.index.coerce_to_pyobject(env)
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
else:
if self.base.type.is_ptr or self.base.type.is_array:
"Invalid index type '%s'" %
self.index.type)
+ def gil_check(self, env):
+ if not self.is_buffer_access:
+ if self.base.type.is_pyobject:
+ self._gil_check(env)
+
gil_message = "Indexing Python object"
def check_const_addr(self):
self.start = self.start.coerce_to(c_int, env)
if self.stop:
self.stop = self.stop.coerce_to(c_int, env)
- self.gil_check(env)
self.is_temp = 1
+ gil_check = ExprNode._gil_check
gil_message = "Slicing Python object"
def generate_result_code(self, code):
self.stop = self.stop.coerce_to_pyobject(env)
self.step = self.step.coerce_to_pyobject(env)
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing Python slice object"
class CallNode(NewTempExprNode):
- def gil_check(self, env):
- # Make sure we're not in a nogil environment
- if env.nogil:
- error(self.pos, "Calling gil-requiring function without gil")
-
def analyse_as_type_constructor(self, env):
type = self.function.analyse_as_type(env)
if type and type.is_struct_or_union:
self.coerce_to(type, env)
return True
+ def gil_check(self, env):
+ func_type = self.function_type()
+ if func_type.is_pyobject:
+ self._gil_check(env)
+ elif not getattr(func_type, 'nogil', False):
+ self._gil_check(env)
+
+ gil_message = "Calling gil-requiring function"
+
class SimpleCallNode(CallNode):
# Function call without keyword, * or ** args.
self.arg_tuple.analyse_types(env)
self.args = None
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
else:
for arg in self.args:
if func_type.exception_check == '+':
if func_type.exception_value is None:
env.use_utility_code(cpp_exception_utility_code)
- # Check gil
- if not func_type.nogil:
- self.gil_check(env)
def calculate_result_code(self):
return self.c_call_code()
subexprs = ['function', 'positional_args', 'keyword_args', 'starstar_arg']
+ gil_check = CallNode._gil_check
+
def compile_time_value(self, denv):
function = self.function.compile_time_value(denv)
positional_args = self.positional_args.compile_time_value(denv)
self.starstar_arg = \
self.starstar_arg.coerce_to_pyobject(env)
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
def generate_result_code(self, code):
self.arg.analyse_types(env)
self.arg = self.arg.coerce_to_pyobject(env)
self.type = tuple_type
- self.gil_check(env)
self.is_temp = 1
+ gil_check = ExprNode._gil_check
gil_message = "Constructing Python tuple"
def generate_result_code(self, code):
self.type = py_object_type
self.is_py_attr = 1
self.interned_attr_cname = env.intern_identifier(self.attribute)
- self.gil_check(env)
else:
if not obj_type.is_error:
error(self.pos,
"Object of type '%s' has no attribute '%s'" %
(obj_type, self.attribute))
+ def gil_check(self, env):
+ if self.is_py_attr:
+ self._gil_check(env)
+
gil_message = "Accessing Python attribute"
def is_simple(self):
is_sequence_constructor = 1
unpacked_items = None
-
+
def compile_time_value_list(self, denv):
return [arg.compile_time_value(denv) for arg in self.args]
if not skip_children: arg.analyse_types(env)
self.args[i] = arg.coerce_to_pyobject(env)
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
def analyse_target_types(self, env):
arg.analyse_types(env)
self.args[i] = arg.coerce_to_pyobject(env)
self.type = set_type
- self.gil_check(env)
self.is_temp = 1
def calculate_constant_result(self):
self.type = dict_type
for item in self.key_value_pairs:
item.analyse_types(env)
- self.gil_check(env)
self.obj_conversion_errors = held_errors()
release_errors(ignore=True)
self.is_temp = 1
# value ExprNode
subexprs = ['key', 'value']
+ gil_check = None # handled by DictNode
+
def calculate_constant_result(self):
self.constant_result = (
self.key.constant_result, self.value.constant_result)
self.doc = self.doc.coerce_to_pyobject(env)
self.module_name = env.global_scope().qualified_name
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
env.use_utility_code(create_class_utility_code);
def analyse_types(self, env):
self.function.analyse_types(env)
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing an unbound method"
def analyse_types(self, env):
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
gil_message = "Constructing Python function"
if self.is_py_operation():
self.coerce_operand_to_pyobject(env)
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
else:
self.analyse_c_operation(env)
def is_py_operation(self):
return self.operand.type.is_pyobject
-
+
+ def gil_check(self, env):
+ if self.is_py_operation():
+ self._gil_check(env)
+
def coerce_operand_to_pyobject(self, env):
self.operand = self.operand.coerce_to_pyobject(env)
elif from_py and to_py:
if self.typecheck and self.type.is_extension_type:
self.operand = PyTypeTestNode(self.operand, self.type, env)
-
+
+ def gil_check(self, env):
+ if self.type.is_pyobject and self.is_temp:
+ self._gil_check(env)
+
def check_const(self):
self.operand.check_const()
if self.is_py_operation():
self.coerce_operands_to_pyobjects(env)
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
if Options.incref_local_binop and self.operand1.type.is_pyobject:
self.operand1 = self.operand1.coerce_to_temp(env)
def is_py_operation(self):
return (self.operand1.type.is_pyobject
or self.operand2.type.is_pyobject)
+
+ def gil_check(self, env):
+ if self.is_py_operation():
+ self._gil_check(env)
def coerce_operands_to_pyobjects(self, env):
self.operand1 = self.operand1.coerce_to_pyobject(env)
self.operand1 = self.operand1.coerce_to_pyobject(env)
self.operand2 = self.operand2.coerce_to_pyobject(env)
self.type = py_object_type
- self.gil_check(env)
else:
self.operand1 = self.operand1.coerce_to_boolean(env)
self.operand2 = self.operand2.coerce_to_boolean(env)
assert dst_type.is_extension_type or dst_type.is_builtin_type, "PyTypeTest on non extension type"
CoercionNode.__init__(self, arg)
self.type = dst_type
- self.gil_check(env)
self.result_ctype = arg.ctype()
+ gil_check = CoercionNode._gil_check
gil_message = "Python type test"
def analyse_types(self, env):
def __init__(self, arg, env):
CoercionNode.__init__(self, arg)
self.type = py_object_type
- self.gil_check(env)
self.is_temp = 1
if not arg.type.to_py_function or not arg.type.create_convert_utility_code(env):
error(arg.pos,
"Cannot convert '%s' to Python object" % arg.type)
-
+
gil_message = "Converting to Python object"
-
+
def coerce_to_boolean(self, env):
return self.arg.coerce_to_boolean(env).coerce_to_temp(env)
CoercionNode.__init__(self, arg)
self.type = PyrexTypes.c_bint_type
if arg.type.is_pyobject:
- if env.nogil:
- self.gil_error()
self.is_temp = 1
+ def gil_check(self, env):
+ if self.arg.type.is_pyobject:
+ self._gil_check(env)
+
gil_message = "Truth-testing Python object"
def check_const(self):
self.type = self.arg.type
self.is_temp = 1
if self.type.is_pyobject:
- self.gil_check(env)
self.result_ctype = py_object_type
gil_message = "Creating temporary Python reference"
# node is responsible for doing those things.
subexprs = [] # Arg is not considered a subexpr
+ gil_check = None
def __init__(self, arg):
CoercionNode.__init__(self, arg)
gil_message = "Operation"
- def gil_check(self, env):
+ gil_check = None
+ def _gil_check(self, env):
if env.nogil:
self.gil_error()
# Catch attempted C-style func(void) decl
if type.is_void:
error(arg_node.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
-# if type.is_pyobject and self.nogil:
-# error(self.pos,
-# "Function with Python argument cannot be declared nogil")
func_type_args.append(
PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
if arg_node.default:
if not arg.name:
error(arg.pos, "Missing argument name")
self.declare_argument(env, arg)
-
+
def need_gil_acquisition(self, lenv):
+ return self.type.with_gil
+
+ def gil_check(self, env):
type = self.type
- with_gil = self.type.with_gil
+ with_gil = type.with_gil
if type.nogil and not with_gil:
if type.return_type.is_pyobject:
error(self.pos,
"Function with Python return type cannot be declared nogil")
- for entry in lenv.var_entries + lenv.temp_entries:
+ for entry in env.var_entries + env.temp_entries:
if entry.type.is_pyobject:
error(self.pos, "Function declared nogil has Python locals or temporaries")
- return with_gil
def analyse_expressions(self, env):
self.analyse_default_values(env)
env.use_utility_code(printing_utility_code)
if len(self.arg_tuple.args) == 1 and self.append_newline:
env.use_utility_code(printing_one_utility_code)
- self.gil_check(env)
+ gil_check = StatNode._gil_check
gil_message = "Python print statement"
def generate_execution_code(self, code):
self.temp_result = env.allocate_temp_pyobject()
env.release_temp(self.temp_result)
env.use_utility_code(Builtin.pyexec_utility_code)
- self.gil_check(env)
+ gil_check = StatNode._gil_check
gil_message = "Python exec statement"
def generate_execution_code(self, code):
def analyse_expressions(self, env):
for arg in self.args:
arg.analyse_target_expression(env, None)
- if arg.type.is_pyobject:
- self.gil_check(env)
- else:
+ if not arg.type.is_pyobject:
error(arg.pos, "Deletion of non-Python object")
#arg.release_target_temp(env)
+ def gil_check(self, env):
+ for arg in self.args:
+ if arg.type.is_pyobject:
+ self._gil_check(env)
+
gil_message = "Deleting Python object"
def generate_execution_code(self, code):
and not return_type.is_pyobject
and not return_type.is_returncode):
error(self.pos, "Return value required")
- if return_type.is_pyobject:
- self.gil_check(env)
+
+ def gil_check(self, env):
+ if self.return_type.is_pyobject:
+ self._gil_check(env)
gil_message = "Returning Python object"
self.exc_tb.release_temp(env)
env.use_utility_code(raise_utility_code)
env.use_utility_code(restore_exception_utility_code)
- self.gil_check(env)
+ gil_check = StatNode._gil_check
gil_message = "Raising exception"
def generate_execution_code(self, code):
child_attrs = []
def analyse_expressions(self, env):
- self.gil_check(env)
env.use_utility_code(raise_utility_code)
env.use_utility_code(restore_exception_utility_code)
+ gil_check = StatNode._gil_check
gil_message = "Raising exception"
def generate_execution_code(self, code):
self.cond.release_temp(env)
if self.value:
self.value.release_temp(env)
- self.gil_check(env)
#env.recycle_pending_temps() # TEMPORARY
+ gil_check = StatNode._gil_check
gil_message = "Raising exception"
def generate_execution_code(self, code):
except_clause.analyse_declarations(env)
if self.else_clause:
self.else_clause.analyse_declarations(env)
- self.gil_check(env)
env.use_utility_code(reset_exception_utility_code)
-
+
def analyse_expressions(self, env):
self.body.analyse_expressions(env)
self.cleanup_list = env.free_temp_entries[:]
self.has_default_clause = default_clause_seen
if self.else_clause:
self.else_clause.analyse_expressions(env)
- self.gil_check(env)
+ gil_check = StatNode._gil_check
gil_message = "Try-except statement"
def generate_execution_code(self, code):
self.body.analyse_expressions(env)
self.cleanup_list = env.free_temp_entries[:]
self.finally_clause.analyse_expressions(env)
- self.gil_check(env)
+ gil_check = StatNode._gil_check
gil_message = "Try-finally statement"
def generate_execution_code(self, code):
# 'with gil' or 'with nogil' statement
#
# state string 'gil' or 'nogil'
-
- child_attrs = []
+
+# child_attrs = []
preserve_exception = 0