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): ...@@ -721,18 +721,22 @@ class ExprNode(Node):
def addr_not_const(self): def addr_not_const(self):
error(self.pos, "Address is not constant") error(self.pos, "Address is not constant")
def is_rhs_locked(self): def is_rhs_locked(self, env):
return True return True
def is_lhs_locked(self): def is_lhs_locked(self, env):
return True return True
def check_rhs_locked(self): def check_rhs_locked(self, env):
if not self.is_rhs_locked(): 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)") 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): def check_lhs_locked(self, env):
if not self.is_lhs_locked(): 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)") error(self.pos, "This lhs is not correctly locked (write lock needed)")
# ----------------- Result Allocation ----------------- # ----------------- Result Allocation -----------------
...@@ -5875,10 +5879,6 @@ class SimpleCallNode(CallNode): ...@@ -5875,10 +5879,6 @@ class SimpleCallNode(CallNode):
arg.exact_builtin_type = False arg.exact_builtin_type = False
args[0] = arg args[0] = arg
# Check arguments for cypclass locks
for arg in args:
arg.check_rhs_locked()
# Coerce arguments # Coerce arguments
some_args_in_temps = False some_args_in_temps = False
for i in range(min(max_nargs, actual_nargs)): for i in range(min(max_nargs, actual_nargs)):
...@@ -6001,9 +6001,6 @@ class SimpleCallNode(CallNode): ...@@ -6001,9 +6001,6 @@ class SimpleCallNode(CallNode):
self.overflowcheck = env.directives['overflowcheck'] self.overflowcheck = env.directives['overflowcheck']
def is_rhs_locked(self):
return self.function.is_rhs_locked()
def calculate_result_code(self): def calculate_result_code(self):
return self.c_call_code() return self.c_call_code()
...@@ -6932,6 +6929,7 @@ class AttributeNode(ExprNode): ...@@ -6932,6 +6929,7 @@ class AttributeNode(ExprNode):
is_memslice_transpose = False is_memslice_transpose = False
is_special_lookup = False is_special_lookup = False
is_py_attr = 0 is_py_attr = 0
needs_autolock = False
def as_cython_attribute(self): def as_cython_attribute(self):
if (isinstance(self.obj, NameNode) and if (isinstance(self.obj, NameNode) and
...@@ -7302,22 +7300,32 @@ class AttributeNode(ExprNode): ...@@ -7302,22 +7300,32 @@ class AttributeNode(ExprNode):
gil_message = "Accessing Python attribute" gil_message = "Accessing Python attribute"
def is_rhs_locked(self): def is_rhs_locked(self, env):
# TODO: some chaining
obj = self.obj obj = self.obj
if hasattr(obj, 'entry') and obj.entry.type.is_cyp_class and (obj.entry.is_variable or obj.entry.is_cfunction)\ 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): 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 return True
def is_lhs_locked(self): def is_lhs_locked(self, env):
# TODO: some chaining
obj = self.obj obj = self.obj
if self.is_lvalue() and hasattr(obj, 'entry') and obj.entry.type.is_cyp_class and not obj.entry.is_wlocked: 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 return True
def is_cimported_module_without_shadow(self, env): def is_cimported_module_without_shadow(self, env):
return self.obj.is_cimported_module_without_shadow(env) return self.obj.is_cimported_module_without_shadow(env)
...@@ -7424,6 +7432,9 @@ class AttributeNode(ExprNode): ...@@ -7424,6 +7432,9 @@ class AttributeNode(ExprNode):
elif self.entry and self.entry.is_cmethod: elif self.entry and self.entry.is_cmethod:
# C method implemented as function call with utility code # C method implemented as function call with utility code
code.globalstate.use_entry_utility_code(self.entry) 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): def generate_disposal_code(self, code):
if self.is_temp and self.type.is_memoryviewslice and self.is_memslice_transpose: if self.is_temp and self.type.is_memoryviewslice and self.is_memslice_transpose:
...@@ -7467,6 +7478,9 @@ class AttributeNode(ExprNode): ...@@ -7467,6 +7478,9 @@ class AttributeNode(ExprNode):
code.put_cygotref(select_code) code.put_cygotref(select_code)
code.put_cyxdecref(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: if not self.type.is_memoryviewslice:
code.putln( code.putln(
"%s = %s;" % ( "%s = %s;" % (
...@@ -12807,6 +12821,12 @@ class PrimaryCmpNode(ExprNode, CmpNode): ...@@ -12807,6 +12821,12 @@ class PrimaryCmpNode(ExprNode, CmpNode):
operand1 = self.operand1.compile_time_value(denv) operand1 = self.operand1.compile_time_value(denv)
return self.cascaded_compile_time_value(operand1, 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): def analyse_types(self, env):
self.operand1 = self.operand1.analyse_types(env) self.operand1 = self.operand1.analyse_types(env)
self.operand2 = self.operand2.analyse_types(env) self.operand2 = self.operand2.analyse_types(env)
...@@ -13073,6 +13093,11 @@ class CascadedCmpNode(Node, CmpNode): ...@@ -13073,6 +13093,11 @@ class CascadedCmpNode(Node, CmpNode):
return self.constant_result is not constant_value_not_set and \ return self.constant_result is not constant_value_not_set and \
self.constant_result is not not_a_constant 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): def analyse_types(self, env):
self.operand2 = self.operand2.analyse_types(env) self.operand2 = self.operand2.analyse_types(env)
if self.cascade: if self.cascade:
......
...@@ -2215,6 +2215,9 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -2215,6 +2215,9 @@ class FuncDefNode(StatNode, BlockNode):
# FIXME ideally use entry.xdecref_cleanup but this currently isn't reliable # FIXME ideally use entry.xdecref_cleanup but this currently isn't reliable
code.put_var_xdecref(entry, have_gil=gil_owned['success']) 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 # Decref any increfed args
for entry in lenv.arg_entries: for entry in lenv.arg_entries:
if entry.type.is_memoryviewslice: if entry.type.is_memoryviewslice:
...@@ -5590,7 +5593,7 @@ class ExprStatNode(StatNode): ...@@ -5590,7 +5593,7 @@ class ExprStatNode(StatNode):
def analyse_expressions(self, env): def analyse_expressions(self, env):
self.expr.result_is_used = False # hint that .result() may safely be left empty self.expr.result_is_used = False # hint that .result() may safely be left empty
self.expr = self.expr.analyse_expressions(env) self.expr = self.expr.analyse_expressions(env)
self.expr.check_rhs_locked() self.expr.check_rhs_locked(env)
# Repeat in case of node replacement. # Repeat in case of node replacement.
self.expr.result_is_used = False # hint that .result() may safely be left empty self.expr.result_is_used = False # hint that .result() may safely be left empty
return self return self
...@@ -5758,8 +5761,8 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -5758,8 +5761,8 @@ class SingleAssignmentNode(AssignmentNode):
self.lhs = self.lhs.analyse_target_types(env) self.lhs = self.lhs.analyse_target_types(env)
self.lhs.gil_assignment_check(env) self.lhs.gil_assignment_check(env)
self.rhs.check_rhs_locked() self.rhs.check_rhs_locked(env)
self.lhs.check_lhs_locked() self.lhs.check_lhs_locked(env)
unrolled_assignment = self.unroll_lhs(env) unrolled_assignment = self.unroll_lhs(env)
if unrolled_assignment: if unrolled_assignment:
return unrolled_assignment return unrolled_assignment
...@@ -5983,9 +5986,11 @@ class CascadedAssignmentNode(AssignmentNode): ...@@ -5983,9 +5986,11 @@ class CascadedAssignmentNode(AssignmentNode):
for i, lhs in enumerate(self.lhs_list): for i, lhs in enumerate(self.lhs_list):
lhs = self.lhs_list[i] = lhs.analyse_target_types(env) lhs = self.lhs_list[i] = lhs.analyse_target_types(env)
lhs.gil_assignment_check(env) lhs.gil_assignment_check(env)
lhs.check_lhs_locked(env)
lhs_types.add(lhs.type) lhs_types.add(lhs.type)
rhs = self.rhs.analyse_types(env) rhs = self.rhs.analyse_types(env)
rhs.check_rhs_locked(env)
# common special case: only one type needed on the LHS => coerce only once # common special case: only one type needed on the LHS => coerce only once
if len(lhs_types) == 1: if len(lhs_types) == 1:
# Avoid coercion for overloaded assignment operators. # Avoid coercion for overloaded assignment operators.
......
...@@ -320,6 +320,7 @@ class Scope(object): ...@@ -320,6 +320,7 @@ class Scope(object):
# pyfunc_entries [Entry] Python function entries # pyfunc_entries [Entry] Python function entries
# cfunc_entries [Entry] C function entries # cfunc_entries [Entry] C function entries
# c_class_entries [Entry] All extension type 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 # cname_to_entry {string : Entry} Temp cname to entry mapping
# return_type PyrexType or None Return type of function owning scope # return_type PyrexType or None Return type of function owning scope
# is_builtin_scope boolean Is the builtin scope of Python/Cython # is_builtin_scope boolean Is the builtin scope of Python/Cython
...@@ -379,6 +380,7 @@ class Scope(object): ...@@ -379,6 +380,7 @@ class Scope(object):
self.cfunc_entries = [] self.cfunc_entries = []
self.c_class_entries = [] self.c_class_entries = []
self.defined_c_classes = [] self.defined_c_classes = []
self.autolocked_entries = []
self.imported_c_classes = {} self.imported_c_classes = {}
self.cname_to_entry = {} self.cname_to_entry = {}
self.identifier_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