[vala] Fix lock statement
- From: Jürg Billeter <juergbi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala] Fix lock statement
- Date: Wed, 24 Mar 2010 07:40:39 +0000 (UTC)
commit 40c1dbfbfedb6c4a6b88df045eb1c2e7bdd38d93
Author: JiÅ?à Zárevúcky <zarevucky jiri gmail com>
Date: Wed Mar 24 08:36:37 2010 +0100
Fix lock statement
This patch converts lock statements into try finally statements to
ensure that unlock is always called.
Fixes bug 582553.
codegen/valaccodebasemodule.vala | 40 +++++++++++++---------
codegen/valaccodegenerator.vala | 4 ++
codegen/valaccodemodule.vala | 4 ++
vala/Makefile.am | 1 +
vala/valacodevisitor.vala | 8 ++++
vala/valaflowanalyzer.vala | 6 +++-
vala/valalockstatement.vala | 39 +++++++++++++++++----
vala/valaunlockstatement.vala | 70 ++++++++++++++++++++++++++++++++++++++
8 files changed, 147 insertions(+), 25 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 89ef3d5..223d49a 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -3400,28 +3400,26 @@ internal class Vala.CCodeBaseModule : CCodeModule {
return "__lock_%s".printf (symname);
}
- public override void visit_lock_statement (LockStatement stmt) {
- var cn = new CCodeFragment ();
+ private CCodeExpression get_lock_expression (Statement stmt, Expression resource) {
CCodeExpression l = null;
- CCodeFunctionCall fc;
- var inner_node = ((MemberAccess)stmt.resource).inner;
- var member = (Member)stmt.resource.symbol_reference;
- var parent = (TypeSymbol) stmt.resource.symbol_reference.parent_symbol;
+ var inner_node = ((MemberAccess)resource).inner;
+ var member = (Member)resource.symbol_reference;
+ var parent = (TypeSymbol)resource.symbol_reference.parent_symbol;
if (member.is_instance_member ()) {
if (inner_node == null) {
l = new CCodeIdentifier ("self");
- } else if (stmt.resource.symbol_reference.parent_symbol != current_type_symbol) {
- l = generate_instance_cast ((CCodeExpression) inner_node.ccodenode, parent);
+ } else if (resource.symbol_reference.parent_symbol != current_type_symbol) {
+ l = generate_instance_cast ((CCodeExpression) inner_node.ccodenode, parent);
} else {
l = (CCodeExpression) inner_node.ccodenode;
}
- l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (stmt.resource.symbol_reference.name));
+ l = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (l, "priv"), get_symbol_lock_name (resource.symbol_reference.name));
} else if (member.is_class_member ()) {
CCodeExpression klass;
- if (current_method != null && current_method.binding == MemberBinding.INSTANCE ||
+ if (current_method != null && current_method.binding == MemberBinding.INSTANCE ||
current_property_accessor != null && current_property_accessor.prop.binding == MemberBinding.INSTANCE ||
(in_constructor && !in_static_or_class_context)) {
var k = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_GET_CLASS"));
@@ -3433,23 +3431,33 @@ internal class Vala.CCodeBaseModule : CCodeModule {
var get_class_private_call = new CCodeFunctionCall (new CCodeIdentifier ("%s_GET_CLASS_PRIVATE".printf(parent.get_upper_case_cname ())));
get_class_private_call.add_argument (klass);
- l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (stmt.resource.symbol_reference.name));
+ l = new CCodeMemberAccess.pointer (get_class_private_call, get_symbol_lock_name (resource.symbol_reference.name));
} else {
- string lock_name = "%s_%s".printf(parent.get_lower_case_cname (), stmt.resource.symbol_reference.name);
+ string lock_name = "%s_%s".printf(parent.get_lower_case_cname (), resource.symbol_reference.name);
l = new CCodeIdentifier (get_symbol_lock_name (lock_name));
}
+ return l;
+ }
- fc = new CCodeFunctionCall (new CCodeIdentifier (((Method) mutex_type.scope.lookup ("lock")).get_cname ()));
+ public override void visit_lock_statement (LockStatement stmt) {
+ var l = get_lock_expression (stmt, stmt.resource);
+
+ var fc = new CCodeFunctionCall (new CCodeIdentifier (((Method) mutex_type.scope.lookup ("lock")).get_cname ()));
fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
+ var cn = new CCodeFragment ();
cn.append (new CCodeExpressionStatement (fc));
+ stmt.ccodenode = cn;
+ }
- cn.append (stmt.body.ccodenode);
+ public override void visit_unlock_statement (UnlockStatement stmt) {
+ var l = get_lock_expression (stmt, stmt.resource);
- fc = new CCodeFunctionCall (new CCodeIdentifier (((Method) mutex_type.scope.lookup ("unlock")).get_cname ()));
+ var fc = new CCodeFunctionCall (new CCodeIdentifier (((Method) mutex_type.scope.lookup ("unlock")).get_cname ()));
fc.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, l));
- cn.append (new CCodeExpressionStatement (fc));
+ var cn = new CCodeFragment ();
+ cn.append (new CCodeExpressionStatement (fc));
stmt.ccodenode = cn;
}
diff --git a/codegen/valaccodegenerator.vala b/codegen/valaccodegenerator.vala
index fd465d1..f8af697 100644
--- a/codegen/valaccodegenerator.vala
+++ b/codegen/valaccodegenerator.vala
@@ -228,6 +228,10 @@ public class Vala.CCodeGenerator : CodeGenerator {
head.visit_lock_statement (stmt);
}
+ public override void visit_unlock_statement (UnlockStatement stmt) {
+ head.visit_unlock_statement (stmt);
+ }
+
public override void visit_delete_statement (DeleteStatement stmt) {
head.visit_delete_statement (stmt);
}
diff --git a/codegen/valaccodemodule.vala b/codegen/valaccodemodule.vala
index d8e88e3..0355e0c 100644
--- a/codegen/valaccodemodule.vala
+++ b/codegen/valaccodemodule.vala
@@ -207,6 +207,10 @@ public abstract class Vala.CCodeModule {
next.visit_lock_statement (stmt);
}
+ public virtual void visit_unlock_statement (UnlockStatement stmt) {
+ next.visit_unlock_statement (stmt);
+ }
+
public virtual void visit_delete_statement (DeleteStatement stmt) {
next.visit_delete_statement (stmt);
}
diff --git a/vala/Makefile.am b/vala/Makefile.am
index 69f0d0a..aa0b861 100644
--- a/vala/Makefile.am
+++ b/vala/Makefile.am
@@ -151,6 +151,7 @@ libvalacore_la_VALASOURCES = \
valatypeparameter.vala \
valatypesymbol.vala \
valaunaryexpression.vala \
+ valaunlockstatement.vala \
valaunresolvedsymbol.vala \
valaunresolvedtype.vala \
valausingdirective.vala \
diff --git a/vala/valacodevisitor.vala b/vala/valacodevisitor.vala
index f11a3ef..55f87d7 100644
--- a/vala/valacodevisitor.vala
+++ b/vala/valacodevisitor.vala
@@ -405,6 +405,14 @@ public abstract class Vala.CodeVisitor {
}
/**
+ * Visit operation called for unlock statements.
+ *
+ * @param stmt an unlock statement
+ */
+ public virtual void visit_unlock_statement (UnlockStatement stmt) {
+ }
+
+ /**
* Visit operation called for delete statements.
*
* @param stmt a delete statement
diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala
index ff5f255..193f610 100644
--- a/vala/valaflowanalyzer.vala
+++ b/vala/valaflowanalyzer.vala
@@ -1010,8 +1010,12 @@ public class Vala.FlowAnalyzer : CodeVisitor {
if (unreachable (stmt)) {
return;
}
+ }
- stmt.body.accept (this);
+ public override void visit_unlock_statement (UnlockStatement stmt) {
+ if (unreachable (stmt)) {
+ return;
+ }
}
public override void visit_expression (Expression expr) {
diff --git a/vala/valalockstatement.vala b/vala/valalockstatement.vala
index 9ad5dfb..da9a0be 100644
--- a/vala/valalockstatement.vala
+++ b/vala/valalockstatement.vala
@@ -1,5 +1,6 @@
/* valalockstatement.vala
*
+ * Copyright (C) 2009 JiÅ?à Zárevúcky
* Copyright (C) 2006-2007 Raffaele Sandrini, Jürg Billeter
*
* This library is free software; you can redistribute it and/or
@@ -16,14 +17,19 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
- * Author:
+ * Authors:
* Raffaele Sandrini <raffaele sandrini ch>
+ * JiÅ?à Zárevúcky <zarevucky jiri gmail com>
*/
using GLib;
/**
- * Represents a lock statement e.g. {{{ lock (a) { f(a) } }}}.
+ * Represents a lock statement e.g. {{{ lock (a); }}} or {{{ lock (a) { f(a); } }}}.
+ *
+ * If the statement is empty, the mutex remains locked until a corresponding UnlockStatement
+ * occurs. Otherwise it's translated into a try/finally statement which unlocks the mutex
+ * after the block is finished.
*/
public class Vala.LockStatement : CodeNode, Statement {
/**
@@ -34,9 +40,9 @@ public class Vala.LockStatement : CodeNode, Statement {
/**
* The statement during its execution the resource is locked.
*/
- public Block body { get; set; }
+ public Block? body { get; set; }
- public LockStatement (Expression resource, Block body, SourceReference? source_reference = null) {
+ public LockStatement (Expression resource, Block? body, SourceReference? source_reference = null) {
this.body = body;
this.source_reference = source_reference;
this.resource = resource;
@@ -44,11 +50,29 @@ public class Vala.LockStatement : CodeNode, Statement {
public override void accept (CodeVisitor visitor) {
resource.accept (visitor);
- body.accept (visitor);
+ if (body != null) {
+ body.accept (visitor);
+ }
visitor.visit_lock_statement (this);
}
public override bool check (SemanticAnalyzer analyzer) {
+ if (body != null) {
+ // if the statement isn't empty, it is converted into a try statement
+
+ var fin_body = new Block (source_reference);
+ fin_body.add_statement (new UnlockStatement (resource, source_reference));
+
+ var block = new Block (source_reference);
+ block.add_statement (new LockStatement (resource, null, source_reference));
+ block.add_statement (new TryStatement (body, fin_body, source_reference));
+
+ var parent_block = (Block) parent_node;
+ parent_block.replace_statement (this, block);
+
+ return block.check (analyzer);
+ }
+
if (checked) {
return !error;
}
@@ -56,11 +80,10 @@ public class Vala.LockStatement : CodeNode, Statement {
checked = true;
resource.check (analyzer);
- body.check (analyzer);
/* resource must be a member access and denote a Lockable */
if (!(resource is MemberAccess && resource.symbol_reference is Lockable)) {
- error = true;
+ error = true;
resource.error = true;
Report.error (resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
return false;
@@ -68,7 +91,7 @@ public class Vala.LockStatement : CodeNode, Statement {
/* parent symbol must be the current class */
if (resource.symbol_reference.parent_symbol != analyzer.current_class) {
- error = true;
+ error = true;
resource.error = true;
Report.error (resource.source_reference, "Only members of the current class are lockable");
}
diff --git a/vala/valaunlockstatement.vala b/vala/valaunlockstatement.vala
new file mode 100644
index 0000000..e0ae1a0
--- /dev/null
+++ b/vala/valaunlockstatement.vala
@@ -0,0 +1,70 @@
+/* valaunlockstatement.vala
+ *
+ * Copyright (C) 2009 JiÅ?à Zárevúcky, Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * JiÅ?à Zárevúcky <zarevucky jiri gmail com>
+ */
+
+/**
+ * Represents an unlock statement e.g. {{{ unlock (a); }}}.
+ */
+public class Vala.UnlockStatement : CodeNode, Statement {
+ /**
+ * Expression representing the resource to be unlocked.
+ */
+ public Expression resource { get; set; }
+
+ public UnlockStatement (Expression resource, SourceReference? source_reference = null) {
+ this.source_reference = source_reference;
+ this.resource = resource;
+ }
+
+ public override void accept (CodeVisitor visitor) {
+ resource.accept (visitor);
+ visitor.visit_unlock_statement (this);
+ }
+
+ public override bool check (SemanticAnalyzer analyzer) {
+ if (checked) {
+ return !error;
+ }
+
+ checked = true;
+
+ resource.check (analyzer);
+
+ /* resource must be a member access and denote a Lockable */
+ if (!(resource is MemberAccess && resource.symbol_reference is Lockable)) {
+ error = true;
+ resource.error = true;
+ Report.error (resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
+ return false;
+ }
+
+ /* parent symbol must be the current class */
+ if (resource.symbol_reference.parent_symbol != analyzer.current_class) {
+ error = true;
+ resource.error = true;
+ Report.error (resource.source_reference, "Only members of the current class are lockable");
+ }
+
+ ((Lockable) resource.symbol_reference).set_lock_used (true);
+
+ return !error;
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]