OSDN Git Service

Fix determinism for app images
authorMathieu Chartier <mathieuc@google.com>
Fri, 12 May 2017 23:07:28 +0000 (16:07 -0700)
committerMathieu Chartier <mathieuc@google.com>
Tue, 16 May 2017 18:10:29 +0000 (18:10 +0000)
Clear the dalvik.system.DexFile cookie to make the long array
unreachable before the GC.

Test: test-art-host
Test: Ran 10x: mma -j40 && shasum $OUT/system/framework/oat/arm64/services.* && rm $OUT/system/framework/oat/arm64/services.* && rm $OUT/obj/JAVA_LIBRARIES/services_intermediates/oat/arm64/*

Bug: 34090128

(cherry picked from commit 3738e98cb8833b24e998ec3b6906bf58850741c3)

Change-Id: I5a872de3e907461803a77254902d78ff6e657b43

compiler/image_writer.cc
runtime/class_linker.cc

index 952a7c6..4d6db47 100644 (file)
@@ -48,6 +48,7 @@
 #include "image.h"
 #include "imt_conflict_table.h"
 #include "intern_table.h"
+#include "jni_internal.h"
 #include "linear_alloc.h"
 #include "lock_word.h"
 #include "mirror/array-inl.h"
@@ -114,15 +115,19 @@ bool ImageWriter::IsInBootOatFile(const void* ptr) const {
   return false;
 }
 
-static void CheckNoDexObjectsCallback(Object* obj, void* arg ATTRIBUTE_UNUSED)
+static void ClearDexFileCookieCallback(Object* obj, void* arg ATTRIBUTE_UNUSED)
     REQUIRES_SHARED(Locks::mutator_lock_) {
+  DCHECK(obj != nullptr);
   Class* klass = obj->GetClass();
-  CHECK_NE(Class::PrettyClass(klass), "com.android.dex.Dex");
+  if (klass == WellKnownClasses::ToClass(WellKnownClasses::dalvik_system_DexFile)) {
+    ArtField* field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexFile_cookie);
+    // Null out the cookie to enable determinism. b/34090128
+    field->SetObject</*kTransactionActive*/false>(obj, nullptr);
+  }
 }
 
-static void CheckNoDexObjects() {
-  ScopedObjectAccess soa(Thread::Current());
-  Runtime::Current()->GetHeap()->VisitObjects(CheckNoDexObjectsCallback, nullptr);
+static void ClearDexFileCookies() REQUIRES_SHARED(Locks::mutator_lock_) {
+  Runtime::Current()->GetHeap()->VisitObjects(ClearDexFileCookieCallback, nullptr);
 }
 
 bool ImageWriter::PrepareImageAddressSpace() {
@@ -131,23 +136,18 @@ bool ImageWriter::PrepareImageAddressSpace() {
   {
     ScopedObjectAccess soa(Thread::Current());
     PruneNonImageClasses();  // Remove junk
-    if (!compile_app_image_) {
+    if (compile_app_image_) {
+      // Clear dex file cookies for app images to enable app image determinism. This is required
+      // since the cookie field contains long pointers to DexFiles which are not deterministic.
+      // b/34090128
+      ClearDexFileCookies();
+    } else {
       // Avoid for app image since this may increase RAM and image size.
       ComputeLazyFieldsForImageClasses();  // Add useful information
     }
   }
   heap->CollectGarbage(false);  // Remove garbage.
 
-  // Dex caches must not have their dex fields set in the image. These are memory buffers of mapped
-  // dex files.
-  //
-  // We may open them in the unstarted-runtime code for class metadata. Their fields should all be
-  // reset in PruneNonImageClasses and the objects reclaimed in the GC. Make sure that's actually
-  // true.
-  if (kIsDebugBuild) {
-    CheckNoDexObjects();
-  }
-
   if (kIsDebugBuild) {
     ScopedObjectAccess soa(Thread::Current());
     CheckNonImageClassesRemoved();
index 3ecf595..694c113 100644 (file)
@@ -8705,6 +8705,8 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self,
     DCHECK(h_long_array != nullptr);
     h_long_array->Set(kDexFileIndexStart, reinterpret_cast<intptr_t>(dex_file));
 
+    // Note that this creates a finalizable dalvik.system.DexFile object and a corresponding
+    // FinalizerReference which will never get cleaned up without a started runtime.
     Handle<mirror::Object> h_dex_file = hs2.NewHandle(
         cookie_field->GetDeclaringClass()->AllocObject(self));
     DCHECK(h_dex_file != nullptr);