Add memory barrier for final instance fields.

Change-Id: I1a02f0f75e974f4c84d61254da05480c20ff881c
diff --git a/src/compiler.cc b/src/compiler.cc
index b125fdf..aa2ec40 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -285,6 +285,7 @@
                    bool dump_stats, bool dump_timings)
     : compiler_backend_(compiler_backend),
       instruction_set_(instruction_set),
+      freezing_constructor_lock_("freezing constructor lock"),
       compiled_classes_lock_("compiled classes lock"),
       compiled_methods_lock_("compiled method lock"),
       compiled_invoke_stubs_lock_("compiled invoke stubs lock"),
@@ -500,8 +501,8 @@
   DCHECK(!Runtime::Current()->IsStarted());
   Thread* self = Thread::Current();
   jobject class_loader;
-  const DexCache* dex_cache;
   const DexFile* dex_file;
+  uint32_t class_def_idx;
   {
     ScopedObjectAccessUnchecked soa(self);
     ScopedLocalRef<jobject>
@@ -509,8 +510,9 @@
                     soa.AddLocalReference<jobject>(method->GetDeclaringClass()->GetClassLoader()));
     class_loader = soa.Env()->NewGlobalRef(local_class_loader.get());
     // Find the dex_file
-    dex_cache = method->GetDeclaringClass()->GetDexCache();
-    dex_file = dex_cache->GetDexFile();
+    MethodHelper mh(method);
+    dex_file = &mh.GetDexFile();
+    class_def_idx = mh.GetClassDefIndex();
   }
   self->TransitionFromRunnableToSuspended(kNative);
 
@@ -524,7 +526,7 @@
   uint32_t method_idx = method->GetDexMethodIndex();
   const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
   CompileMethod(code_item, method->GetAccessFlags(), method->GetInvokeType(),
-                method_idx, class_loader, *dex_file);
+                class_def_idx, method_idx, class_loader, *dex_file);
 
   self->GetJniEnv()->DeleteGlobalRef(class_loader);
 
@@ -1124,7 +1126,14 @@
     }
     it.Next();
   }
+  // If an instance field is final then we need to have a barrier on the return, static final
+  // fields are assigned within the lock held for class initialization.
+  bool requires_constructor_barrier = false;
   while (it.HasNextInstanceField()) {
+    if ((it.GetMemberAccessFlags() & kAccFinal) != 0) {
+      requires_constructor_barrier = true;
+    }
+
     Field* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache,
                                               class_loader, false);
     if (field == NULL) {
@@ -1133,9 +1142,14 @@
     }
     it.Next();
   }
+  if (requires_constructor_barrier) {
+    context->GetCompiler()->AddRequiresConstructorBarrier(soa.Self(), context->GetDexFile(),
+                                                          class_def_index);
+  }
   while (it.HasNextDirectMethod()) {
     AbstractMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache,
-                                                 class_loader, NULL, it.GetMethodInvokeType(class_def));
+                                                         class_loader, NULL,
+                                                         it.GetMethodInvokeType(class_def));
     if (method == NULL) {
       CHECK(self->IsExceptionPending());
       self->ClearException();
@@ -1144,7 +1158,8 @@
   }
   while (it.HasNextVirtualMethod()) {
     AbstractMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache,
-                                                 class_loader, NULL, it.GetMethodInvokeType(class_def));
+                                                         class_loader, NULL,
+                                                         it.GetMethodInvokeType(class_def));
     if (method == NULL) {
       CHECK(self->IsExceptionPending());
       self->ClearException();
@@ -1570,8 +1585,8 @@
     }
     previous_direct_method_idx = method_idx;
     context->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
-                                          it.GetMethodInvokeType(class_def), method_idx,
-                                          class_loader, dex_file);
+                                          it.GetMethodInvokeType(class_def), class_def_index,
+                                          method_idx, class_loader, dex_file);
     it.Next();
   }
   // Compile virtual methods
@@ -1586,8 +1601,8 @@
     }
     previous_virtual_method_idx = method_idx;
     context->GetCompiler()->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
-                                          it.GetMethodInvokeType(class_def), method_idx,
-                                          class_loader, dex_file);
+                                          it.GetMethodInvokeType(class_def), class_def_index,
+                                          method_idx, class_loader, dex_file);
     it.Next();
   }
   DCHECK(!it.HasNext());
@@ -1609,8 +1624,8 @@
 }
 
 void Compiler::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
-                             InvokeType invoke_type, uint32_t method_idx, jobject class_loader,
-                             const DexFile& dex_file) {
+                             InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx,
+                             jobject class_loader, const DexFile& dex_file) {
   CompiledMethod* compiled_method = NULL;
   uint64_t start_ns = NanoTime();
 
@@ -1619,8 +1634,8 @@
     CHECK(compiled_method != NULL);
   } else if ((access_flags & kAccAbstract) != 0) {
   } else {
-    compiled_method = (*compiler_)(*this, code_item, access_flags, invoke_type, method_idx,
-                                   class_loader, dex_file);
+    compiled_method = (*compiler_)(*this, code_item, access_flags, invoke_type, class_def_idx,
+                                   method_idx, class_loader, dex_file);
     CHECK(compiled_method != NULL) << PrettyMethod(method_idx, dex_file);
   }
   uint64_t duration_ns = NanoTime() - start_ns;
@@ -1748,4 +1763,17 @@
   set_bitcode_file_name(*this, filename);
 }
 
+
+void Compiler::AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file,
+                                             size_t class_def_index) {
+  MutexLock mu(self, freezing_constructor_lock_);
+  freezing_constructor_classes_.insert(ClassReference(dex_file, class_def_index));
+}
+
+bool Compiler::RequiresConstructorBarrier(Thread* self, const DexFile* dex_file,
+                                          size_t class_def_index) {
+  MutexLock mu(self, freezing_constructor_lock_);
+  return freezing_constructor_classes_.count(ClassReference(dex_file, class_def_index)) != 0;
+}
+
 }  // namespace art
diff --git a/src/compiler.h b/src/compiler.h
index 8facc96..ad2a254 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -131,6 +131,9 @@
 
   const CompiledInvokeStub* FindProxyStub(const char* shorty) const;
 
+  void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index);
+  bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index);
+
   // Callbacks from compiler to see what runtime checks must be generated.
 
   bool CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file, uint32_t type_idx)
@@ -296,7 +299,7 @@
                       ThreadPool& thread_pool, TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
   void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags,
-                     InvokeType invoke_type, uint32_t method_idx,
+                     InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx,
                      jobject class_loader, const DexFile& dex_file)
       LOCKS_EXCLUDED(compiled_methods_lock_);
 
@@ -315,18 +318,22 @@
 
   InstructionSet instruction_set_;
 
+  // All class references that require
+  mutable Mutex freezing_constructor_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  std::set<ClassReference> freezing_constructor_classes_ GUARDED_BY(freezing_constructor_lock_);
+
   typedef SafeMap<const ClassReference, CompiledClass*> ClassTable;
-  // All class references that this compiler has compiled
+  // All class references that this compiler has compiled.
   mutable Mutex compiled_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   ClassTable compiled_classes_ GUARDED_BY(compiled_classes_lock_);
 
   typedef SafeMap<const MethodReference, CompiledMethod*> MethodTable;
-  // All method references that this compiler has compiled
+  // All method references that this compiler has compiled.
   mutable Mutex compiled_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   MethodTable compiled_methods_ GUARDED_BY(compiled_methods_lock_);
 
   typedef SafeMap<std::string, const CompiledInvokeStub*> InvokeStubTable;
-  // Invocation stubs created to allow invocation of the compiled methods
+  // Invocation stubs created to allow invocation of the compiled methods.
   mutable Mutex compiled_invoke_stubs_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   InvokeStubTable compiled_invoke_stubs_ GUARDED_BY(compiled_invoke_stubs_lock_);
 
@@ -355,8 +362,8 @@
   typedef CompiledMethod* (*CompilerFn)(Compiler& compiler,
                                         const DexFile::CodeItem* code_item,
                                         uint32_t access_flags, InvokeType invoke_type,
-                                        uint32_t method_idx, jobject class_loader,
-                                        const DexFile& dex_file);
+                                        uint32_t class_dex_idx, uint32_t method_idx,
+                                        jobject class_loader, const DexFile& dex_file);
   CompilerFn compiler_;
 
   void* compiler_context_;
diff --git a/src/compiler/codegen/mir_to_lir.cc b/src/compiler/codegen/mir_to_lir.cc
index acdeafe..1d64661 100644
--- a/src/compiler/codegen/mir_to_lir.cc
+++ b/src/compiler/codegen/mir_to_lir.cc
@@ -86,6 +86,11 @@
       cg->GenMoveException(cu, rl_dest);
       break;
     case Instruction::RETURN_VOID:
+      if (((cu->access_flags & kAccConstructor) != 0) &&
+          cu->compiler->RequiresConstructorBarrier(Thread::Current(), cu->dex_file,
+                                                   cu->class_def_idx)) {
+        cg->GenMemBarrier(cu, kStoreStore);
+      }
       if (!(cu->attrs & METHOD_IS_LEAF)) {
         cg->GenSuspendTest(cu, opt_flags);
       }
diff --git a/src/compiler/compiler_ir.h b/src/compiler/compiler_ir.h
index 9c67cd5..c5f5107 100644
--- a/src/compiler/compiler_ir.h
+++ b/src/compiler/compiler_ir.h
@@ -277,6 +277,7 @@
       class_linker(NULL),
       dex_file(NULL),
       class_loader(NULL),
+      class_def_idx(0),
       method_idx(0),
       code_item(NULL),
       access_flags(0),
@@ -345,6 +346,7 @@
       mstats(NULL),
       checkstats(NULL),
       gen_bitcode(false),
+      llvm_info(NULL),
       context(NULL),
       module(NULL),
       func(NULL),
@@ -368,6 +370,7 @@
   ClassLinker* class_linker;           // Linker to resolve fields and methods.
   const DexFile* dex_file;             // DexFile containing the method being compiled.
   jobject class_loader;                // compiling method's class loader.
+  uint32_t class_def_idx;              // compiling method's defining class definition index.
   uint32_t method_idx;                 // compiling method's index into method_ids of DexFile.
   const DexFile::CodeItem* code_item;  // compiling method's DexFile code_item.
   uint32_t access_flags;               // compiling method's access flags.
diff --git a/src/compiler/frontend.cc b/src/compiler/frontend.cc
index 9d30b6a..e6f29ef 100644
--- a/src/compiler/frontend.cc
+++ b/src/compiler/frontend.cc
@@ -773,8 +773,8 @@
                                      const CompilerBackend compiler_backend,
                                      const DexFile::CodeItem* code_item,
                                      uint32_t access_flags, InvokeType invoke_type,
-                                     uint32_t method_idx, jobject class_loader,
-                                     const DexFile& dex_file,
+                                     uint32_t class_def_idx, uint32_t method_idx,
+                                     jobject class_loader, const DexFile& dex_file,
                                      LLVMInfo* llvm_info)
 {
   VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
@@ -792,6 +792,7 @@
   cu->compiler = &compiler;
   cu->class_linker = class_linker;
   cu->dex_file = &dex_file;
+  cu->class_def_idx = class_def_idx;
   cu->method_idx = method_idx;
   cu->code_item = code_item;
   cu->access_flags = access_flags;
@@ -1219,12 +1220,12 @@
                                  const CompilerBackend backend,
                                  const DexFile::CodeItem* code_item,
                                  uint32_t access_flags, InvokeType invoke_type,
-                                 uint32_t method_idx, jobject class_loader,
+                                 uint32_t class_def_idx, uint32_t method_idx, jobject class_loader,
                                  const DexFile& dex_file,
                                  LLVMInfo* llvm_info)
 {
-  return CompileMethod(compiler, backend, code_item, access_flags, invoke_type, method_idx, class_loader,
-                       dex_file, llvm_info);
+  return CompileMethod(compiler, backend, code_item, access_flags, invoke_type, class_def_idx,
+                       method_idx, class_loader, dex_file, llvm_info);
 }
 
 }  // namespace art
@@ -1233,11 +1234,12 @@
     ArtQuickCompileMethod(art::Compiler& compiler,
                           const art::DexFile::CodeItem* code_item,
                           uint32_t access_flags, art::InvokeType invoke_type,
-                          uint32_t method_idx, jobject class_loader,
+                          uint32_t class_def_idx, uint32_t method_idx, jobject class_loader,
                           const art::DexFile& dex_file)
 {
   // TODO: check method fingerprint here to determine appropriate backend type.  Until then, use build default
   art::CompilerBackend backend = compiler.GetCompilerBackend();
   return art::CompileOneMethod(compiler, backend, code_item, access_flags, invoke_type,
-                               method_idx, class_loader, dex_file, NULL /* use thread llvm_info */);
+                               class_def_idx, method_idx, class_loader, dex_file,
+                               NULL /* use thread llvm_info */);
 }
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index 954e2f4..6de10e6 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -259,9 +259,11 @@
                                                  const art::DexFile::CodeItem* code_item,
                                                  uint32_t access_flags,
                                                  art::InvokeType invoke_type,
+                                                 uint32_t class_def_idx,
                                                  uint32_t method_idx,
                                                  jobject class_loader,
                                                  const art::DexFile& dex_file) {
+  UNUSED(class_def_idx);  // TODO: this is used with Compiler::RequiresConstructorBarrier.
   art::ClassLinker *class_linker = art::Runtime::Current()->GetClassLinker();
 
   art::OatCompilationUnit oat_compilation_unit(