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