Commit 8142966e authored by gsamain's avatar gsamain Committed by Xavier Thompson

Messy commit: handle autolocked cyobj + delegate lock checking to subexpr...

Messy commit: handle autolocked cyobj + delegate lock checking to subexpr mechanism + some more checks (bool nodes)
parent ea662de3
......@@ -721,18 +721,22 @@ class ExprNode(Node):
def addr_not_const(self):
error(self.pos, "Address is not constant")
def is_rhs_locked(self):
def is_rhs_locked(self, env):
return True
def is_lhs_locked(self):
def is_lhs_locked(self, env):
return True
def check_rhs_locked(self):
if not self.is_rhs_locked():
def check_rhs_locked(self, env):
for node in self.subexpr_nodes():
node.check_rhs_locked(env)
if not self.is_rhs_locked(env):
error(self.pos, "This rhs is not correctly locked (write lock for non-const methods, read lock is sufficient for everything else)")
def check_lhs_locked(self):
if not self.is_lhs_locked():
def check_lhs_locked(self, env):
for node in self.subexpr_nodes():
node.check_lhs_locked(env)
if not self.is_lhs_locked(env):
error(self.pos, "This lhs is not correctly locked (write lock needed)")
# ----------------- Result Allocation -----------------
......@@ -5875,10 +5879,6 @@ class SimpleCallNode(CallNode):
arg.exact_builtin_type = False
args[0] = arg
# Check arguments for cypclass locks
for arg in args:
arg.check_rhs_locked()
# Coerce arguments
some_args_in_temps = False
for i in range(min(max_nargs, actual_nargs)):
......@@ -6001,9 +6001,6 @@ class SimpleCallNode(CallNode):
self.overflowcheck = env.directives['overflowcheck']
def is_rhs_locked(self):
return self.function.is_rhs_locked()
def calculate_result_code(self):
return self.c_call_code()
......@@ -6932,6 +6929,7 @@ class AttributeNode(ExprNode):
is_memslice_transpose = False
is_special_lookup = False
is_py_attr = 0
needs_autolock = False
def as_cython_attribute(self):
if (isinstance(self.obj, NameNode) and
......@@ -7302,22 +7300,32 @@ class AttributeNode(ExprNode):
gil_message = "Accessing Python attribute"
def is_rhs_locked(self):
# TODO: some chaining
def is_rhs_locked(self, env):
obj = self.obj
if hasattr(obj, 'entry') and obj.entry.type.is_cyp_class and (obj.entry.is_variable or obj.entry.is_cfunction)\
and not (obj.entry.is_rlocked and (not self.entry.is_cfunction or self.entry.type.is_const_method) or obj.entry.is_wlocked):
return False
if obj.entry.type.lock_mode == "autolock":
print "We will autolock here"
self.needs_autolock = True
self.obj.entry.is_wlocked = True
elif obj.entry.type.lock_mode == "checklock":
return False
return True
def is_lhs_locked(self):
# TODO: some chaining
def is_lhs_locked(self, env):
obj = self.obj
if self.is_lvalue() and hasattr(obj, 'entry') and obj.entry.type.is_cyp_class and not obj.entry.is_wlocked:
return False
if obj.entry.type.lock_mode == "autolock":
print "We will autolock here"
self.needs_autolock = True
self.obj.entry.is_wlocked = True
# FIXME: this needs to be obj.result(), because maybe we have to lock
# an intermediate object (obj.att.__autolocked_obj__.attribute)
env.autolocked_entries.append(self.obj.entry)
elif obj.entry.type.lock_mode == "checklock":
return False
return True
def is_cimported_module_without_shadow(self, env):
return self.obj.is_cimported_module_without_shadow(env)
......@@ -7424,6 +7432,9 @@ class AttributeNode(ExprNode):
elif self.entry and self.entry.is_cmethod:
# C method implemented as function call with utility code
code.globalstate.use_entry_utility_code(self.entry)
if self.needs_autolock:
obj_code = self.obj.result_as(self.obj.type)
code.putln("Cy_WLOCK(%s);" % obj_code)
def generate_disposal_code(self, code):
if self.is_temp and self.type.is_memoryviewslice and self.is_memslice_transpose:
......@@ -7467,6 +7478,9 @@ class AttributeNode(ExprNode):
code.put_cygotref(select_code)
code.put_cyxdecref(select_code)
if self.needs_autolock:
code.putln("Cy_WLOCK(%s);" % self.obj.result())
if not self.type.is_memoryviewslice:
code.putln(
"%s = %s;" % (
......@@ -12807,6 +12821,12 @@ class PrimaryCmpNode(ExprNode, CmpNode):
operand1 = self.operand1.compile_time_value(denv)
return self.cascaded_compile_time_value(operand1, denv)
def check_rhs_locked(self, env):
self.operand1.check_rhs_locked(env)
self.operand2.check_rhs_locked(env)
if self.cascade:
self.cascade.check_rhs_locked(env)
def analyse_types(self, env):
self.operand1 = self.operand1.analyse_types(env)
self.operand2 = self.operand2.analyse_types(env)
......@@ -13073,6 +13093,11 @@ class CascadedCmpNode(Node, CmpNode):
return self.constant_result is not constant_value_not_set and \
self.constant_result is not not_a_constant
def check_rhs_locked(self, env):
self.operand2.check_rhs_locked(env)
if self.cascade:
self.cascade.check_rhs_locked(env)
def analyse_types(self, env):
self.operand2 = self.operand2.analyse_types(env)
if self.cascade:
......
......@@ -2215,6 +2215,9 @@ class FuncDefNode(StatNode, BlockNode):
# FIXME ideally use entry.xdecref_cleanup but this currently isn't reliable
code.put_var_xdecref(entry, have_gil=gil_owned['success'])
for entry in lenv.autolocked_entries:
code.putln("Cy_UNLOCK(%s);" % entry.cname)
# Decref any increfed args
for entry in lenv.arg_entries:
if entry.type.is_memoryviewslice:
......@@ -5590,7 +5593,7 @@ class ExprStatNode(StatNode):
def analyse_expressions(self, env):
self.expr.result_is_used = False # hint that .result() may safely be left empty
self.expr = self.expr.analyse_expressions(env)
self.expr.check_rhs_locked()
self.expr.check_rhs_locked(env)
# Repeat in case of node replacement.
self.expr.result_is_used = False # hint that .result() may safely be left empty
return self
......@@ -5758,8 +5761,8 @@ class SingleAssignmentNode(AssignmentNode):
self.lhs = self.lhs.analyse_target_types(env)
self.lhs.gil_assignment_check(env)
self.rhs.check_rhs_locked()
self.lhs.check_lhs_locked()
self.rhs.check_rhs_locked(env)
self.lhs.check_lhs_locked(env)
unrolled_assignment = self.unroll_lhs(env)
if unrolled_assignment:
return unrolled_assignment
......@@ -5983,9 +5986,11 @@ class CascadedAssignmentNode(AssignmentNode):
for i, lhs in enumerate(self.lhs_list):
lhs = self.lhs_list[i] = lhs.analyse_target_types(env)
lhs.gil_assignment_check(env)
lhs.check_lhs_locked(env)
lhs_types.add(lhs.type)
rhs = self.rhs.analyse_types(env)
rhs.check_rhs_locked(env)
# common special case: only one type needed on the LHS => coerce only once
if len(lhs_types) == 1:
# Avoid coercion for overloaded assignment operators.
......
......@@ -320,6 +320,7 @@ class Scope(object):
# pyfunc_entries [Entry] Python function entries
# cfunc_entries [Entry] C function entries
# c_class_entries [Entry] All extension type entries
# autolocked_entries[Entry] All autolocked entries that needs unlocking
# cname_to_entry {string : Entry} Temp cname to entry mapping
# return_type PyrexType or None Return type of function owning scope
# is_builtin_scope boolean Is the builtin scope of Python/Cython
......@@ -379,6 +380,7 @@ class Scope(object):
self.cfunc_entries = []
self.c_class_entries = []
self.defined_c_classes = []
self.autolocked_entries = []
self.imported_c_classes = {}
self.cname_to_entry = {}
self.identifier_to_entry = {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment