We cannot read compilation unit's fields without locking because some
CPUs might reorder memory write operations. For example when thread A
compiles some method and thread B which is running on another CPU
reads the value of ->is_compiled, then thread B might see that
->is_compiled is set 'true' while ->native_ptr is not set yet. Using
mutexes to protect the data ensures that memory barriers are executed
on lock acquisition/release.

Signed-off-by: Tomek Grabiec <tgrab...@gmail.com>
---
 arch/x86/insn-selector.brg |   25 ++++++++++++++++---------
 include/vm/method.h        |   22 ++++++++++++++--------
 2 files changed, 30 insertions(+), 17 deletions(-)

diff --git a/arch/x86/insn-selector.brg b/arch/x86/insn-selector.brg
index aaca31e..96d5414 100644
--- a/arch/x86/insn-selector.brg
+++ b/arch/x86/insn-selector.brg
@@ -2137,16 +2137,23 @@ static void invoke(struct basic_block *s, struct 
tree_node *tree, struct compila
        struct insn *call_insn;
        void *target;
 
-       /*
-        * We can't use vm_method_call_ptr() here because we
-        * later add fixup sites depending on whether target is
-        * trampoline or native.
-        */
-       is_compiled = cu->is_compiled;
-       if (is_compiled)
-               target = vm_method_native_ptr(method);
-       else
+       if (cu == s->b_parent) {
+               /*
+                * This is recursive invocation so we call the trampoline.
+                */
+               is_compiled = false;
                target = vm_method_trampoline_ptr(method);
+       } else {
+               pthread_mutex_lock(&cu->mutex);
+
+               is_compiled = cu->is_compiled;
+               if (is_compiled)
+                       target = vm_method_native_ptr(method);
+               else
+                       target = vm_method_trampoline_ptr(method);
+
+               pthread_mutex_unlock(&cu->mutex);
+       }
 
        call_insn = rel_insn(INSN_CALL_REL, (unsigned long) target);
 
diff --git a/include/vm/method.h b/include/vm/method.h
index 4619cc8..c4ebff5 100644
--- a/include/vm/method.h
+++ b/include/vm/method.h
@@ -114,18 +114,24 @@ static inline void *vm_method_trampoline_ptr(struct 
vm_method *vmm)
        return buffer_ptr(vmm->trampoline->objcode);
 }
 
+/*
+ * XXX: It is not safe to use this function during compilation unless
+ * we are sure that @vmm is not currently being compiled.
+ */
 static inline void *vm_method_call_ptr(struct vm_method *vmm)
 {
-       /*
-        * We don't need to lock on compilation unit here because
-        * ->is_compiled can only change its value from false to true
-        * and before it is set to true the value of ->native_ptr is set
-        * and is constant after that.
-        */
+       void *result;
+
+       pthread_mutex_lock(&vmm->compilation_unit->mutex);
+
        if (vmm->compilation_unit->is_compiled)
-               return vm_method_native_ptr(vmm);
+               result = vm_method_native_ptr(vmm);
+       else
+               result = vm_method_trampoline_ptr(vmm);
+
+       pthread_mutex_unlock(&vmm->compilation_unit->mutex);
 
-       return vm_method_trampoline_ptr(vmm);
+       return result;
 }
 
 #endif
-- 
1.6.0.6


------------------------------------------------------------------------------
_______________________________________________
Jatovm-devel mailing list
Jatovm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jatovm-devel

Reply via email to