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