Merge "1. Fix CFI for quick compiled code in x86 & x86_64; 2. Emit CFI in .eh_frame instead of .debug_frame."
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 59536e2..7e38157 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -81,6 +81,9 @@
 # Do you want run-tests with prebuild enabled?
 ART_TEST_RUN_TEST_PREBUILD ?= true
 
+# Do you want failed tests to have their artifacts cleaned up?
+ART_TEST_RUN_TEST_ALWAYS_CLEAN ?= true
+
 # Define the command run on test failure. $(1) is the name of the test. Executed by the shell.
 define ART_TEST_FAILED
   ( [ -f $(ART_HOST_TEST_DIR)/skipped/$(1) ] || \
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index f0e4d9c..aae9155 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -21,6 +21,7 @@
 #include "mirror/array.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
+#include "mirror/object_reference.h"
 #include "verifier/method_verifier.h"
 #include <functional>
 
@@ -722,6 +723,7 @@
   OpSize load_size = LoadStoreOpSize(is_long_or_double, is_object);
   if (!SLOW_FIELD_PATH && field_info.FastGet()) {
     RegisterClass reg_class = RegClassForFieldLoadStore(load_size, field_info.IsVolatile());
+    // A load of the class will lead to an iget with offset 0.
     DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
     rl_obj = LoadValue(rl_obj, kRefReg);
     GenNullCheck(rl_obj.reg, opt_flags);
@@ -768,7 +770,9 @@
   OpSize store_size = LoadStoreOpSize(is_long_or_double, is_object);
   if (!SLOW_FIELD_PATH && field_info.FastPut()) {
     RegisterClass reg_class = RegClassForFieldLoadStore(store_size, field_info.IsVolatile());
-    DCHECK_GE(field_info.FieldOffset().Int32Value(), 0);
+    // Dex code never writes to the class field.
+    DCHECK_GE(static_cast<uint32_t>(field_info.FieldOffset().Int32Value()),
+              sizeof(mirror::HeapReference<mirror::Class>));
     rl_obj = LoadValue(rl_obj, kRefReg);
     if (is_long_or_double) {
       rl_src = LoadValueWide(rl_src, reg_class);
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 5e784b1..bc13379 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -3949,7 +3949,8 @@
   HeapChunkContext(bool merge, bool native)
       : buf_(16384 - 16),
         type_(0),
-        merge_(merge) {
+        merge_(merge),
+        chunk_overhead_(0) {
     Reset();
     if (native) {
       type_ = CHUNK_TYPE("NHSG");
@@ -3964,6 +3965,14 @@
     }
   }
 
+  void SetChunkOverhead(size_t chunk_overhead) {
+    chunk_overhead_ = chunk_overhead;
+  }
+
+  void ResetStartOfNextChunk() {
+    startOfNextMemoryChunk_ = nullptr;
+  }
+
   void EnsureHeader(const void* chunk_ptr) {
     if (!needHeader_) {
       return;
@@ -4008,7 +4017,7 @@
 
   void Reset() {
     p_ = &buf_[0];
-    startOfNextMemoryChunk_ = NULL;
+    ResetStartOfNextChunk();
     totalAllocationUnits_ = 0;
     needHeader_ = true;
     pieceLenField_ = NULL;
@@ -4035,6 +4044,8 @@
      */
     bool native = type_ == CHUNK_TYPE("NHSG");
 
+    // TODO: I'm not sure using start of next chunk works well with multiple spaces. We shouldn't
+    // count gaps inbetween spaces as free memory.
     if (startOfNextMemoryChunk_ != NULL) {
         // Transmit any pending free memory. Native free memory of
         // over kMaxFreeLen could be because of the use of mmaps, so
@@ -4061,11 +4072,8 @@
     // OLD-TODO: if context.merge, see if this chunk is different from the last chunk.
     // If it's the same, we should combine them.
     uint8_t state = ExamineObject(obj, native);
-    // dlmalloc's chunk header is 2 * sizeof(size_t), but if the previous chunk is in use for an
-    // allocation then the first sizeof(size_t) may belong to it.
-    const size_t dlMallocOverhead = sizeof(size_t);
-    AppendChunk(state, start, used_bytes + dlMallocOverhead);
-    startOfNextMemoryChunk_ = reinterpret_cast<char*>(start) + used_bytes + dlMallocOverhead;
+    AppendChunk(state, start, used_bytes + chunk_overhead_);
+    startOfNextMemoryChunk_ = reinterpret_cast<char*>(start) + used_bytes + chunk_overhead_;
   }
 
   void AppendChunk(uint8_t state, void* ptr, size_t length)
@@ -4154,10 +4162,18 @@
   uint32_t type_;
   bool merge_;
   bool needHeader_;
+  size_t chunk_overhead_;
 
   DISALLOW_COPY_AND_ASSIGN(HeapChunkContext);
 };
 
+static void BumpPointerSpaceCallback(mirror::Object* obj, void* arg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+  const size_t size = RoundUp(obj->SizeOf(), kObjectAlignment);
+  HeapChunkContext::HeapChunkCallback(
+      obj, reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(obj) + size), size, arg);
+}
+
 void Dbg::DdmSendHeapSegments(bool native) {
   Dbg::HpsgWhen when;
   Dbg::HpsgWhat what;
@@ -4198,14 +4214,27 @@
 #endif
   } else {
     gc::Heap* heap = Runtime::Current()->GetHeap();
-    const std::vector<gc::space::ContinuousSpace*>& spaces = heap->GetContinuousSpaces();
-    typedef std::vector<gc::space::ContinuousSpace*>::const_iterator It;
-    for (It cur = spaces.begin(), end = spaces.end(); cur != end; ++cur) {
-      if ((*cur)->IsMallocSpace()) {
-        (*cur)->AsMallocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+    for (const auto& space : heap->GetContinuousSpaces()) {
+      if (space->IsDlMallocSpace()) {
+        // dlmalloc's chunk header is 2 * sizeof(size_t), but if the previous chunk is in use for an
+        // allocation then the first sizeof(size_t) may belong to it.
+        context.SetChunkOverhead(sizeof(size_t));
+        space->AsDlMallocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+      } else if (space->IsRosAllocSpace()) {
+        context.SetChunkOverhead(0);
+        space->AsRosAllocSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
+      } else if (space->IsBumpPointerSpace()) {
+        context.SetChunkOverhead(0);
+        ReaderMutexLock mu(self, *Locks::mutator_lock_);
+        WriterMutexLock mu2(self, *Locks::heap_bitmap_lock_);
+        space->AsBumpPointerSpace()->Walk(BumpPointerSpaceCallback, &context);
+      } else {
+        UNIMPLEMENTED(WARNING) << "Not counting objects in space " << *space;
       }
+      context.ResetStartOfNextChunk();
     }
     // Walk the large objects, these are not in the AllocSpace.
+    context.SetChunkOverhead(0);
     heap->GetLargeObjectsSpace()->Walk(HeapChunkContext::HeapChunkCallback, &context);
   }
 
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 1d80833..bf8cca7 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -1623,12 +1623,12 @@
         std::unique_ptr<MemMap> mem_map(temp_space_->ReleaseMemMap());
         RemoveSpace(temp_space_);
         temp_space_ = nullptr;
+        mem_map->Protect(PROT_READ | PROT_WRITE);
         CreateMainMallocSpace(mem_map.get(), kDefaultInitialSize, mem_map->Size(),
                               mem_map->Size());
         mem_map.release();
         // Compact to the main space from the bump pointer space, don't need to swap semispaces.
         AddSpace(main_space_);
-        main_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
         Compact(main_space_, bump_pointer_space_, kGcCauseCollectorTransition);
         mem_map.reset(bump_pointer_space_->ReleaseMemMap());
         RemoveSpace(bump_pointer_space_);
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 08cff99..d3fcb55 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -19,6 +19,8 @@
 
 #include "dex_cache.h"
 
+#include "base/logging.h"
+#include "mirror/class.h"
 #include "runtime.h"
 
 namespace art {
@@ -41,6 +43,12 @@
   }
 }
 
+inline void DexCache::SetResolvedType(uint32_t type_idx, Class* resolved) {
+  // TODO default transaction support.
+  DCHECK(resolved == nullptr || !resolved->IsErroneous());
+  GetResolvedTypes()->Set(type_idx, resolved);
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index bfd603a..2c5fbcd 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -103,11 +103,8 @@
     return GetResolvedTypes()->Get(type_idx);
   }
 
-  void SetResolvedType(uint32_t type_idx, Class* resolved) ALWAYS_INLINE
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    // TODO default transaction support.
-    GetResolvedTypes()->Set(type_idx, resolved);
-  }
+  void SetResolvedType(uint32_t type_idx, Class* resolved)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   ArtMethod* GetResolvedMethod(uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 91fba4d..d51374b 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -185,7 +185,7 @@
     } else {
       entry = new ReferenceType(klass, descriptor, entries_.size());
     }
-    entries_.push_back(entry);
+    AddEntry(entry);
     return *entry;
   } else {  // Class not resolved.
     // We tried loading the class and failed, this might get an exception raised
@@ -198,7 +198,7 @@
     }
     if (IsValidDescriptor(descriptor)) {
       RegType* entry = new UnresolvedReferenceType(descriptor, entries_.size());
-      entries_.push_back(entry);
+      AddEntry(entry);
       return *entry;
     } else {
       // The descriptor is broken return the unknown type as there's nothing sensible that
@@ -209,7 +209,7 @@
 }
 
 const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* klass, bool precise) {
-  DCHECK(klass != nullptr);
+  DCHECK(klass != nullptr && !klass->IsErroneous());
   if (klass->IsPrimitive()) {
     // Note: precise isn't used for primitive classes. A char is assignable to an int. All
     // primitive classes are final.
@@ -229,7 +229,7 @@
     } else {
       entry = new ReferenceType(klass, descriptor, entries_.size());
     }
-    entries_.push_back(entry);
+    AddEntry(entry);
     return *entry;
   }
 }
@@ -339,7 +339,7 @@
   }
   // Create entry.
   RegType* entry = new UnresolvedMergedType(left.GetId(), right.GetId(), this, entries_.size());
-  entries_.push_back(entry);
+  AddEntry(entry);
   if (kIsDebugBuild) {
     UnresolvedMergedType* tmp_entry = down_cast<UnresolvedMergedType*>(entry);
     std::set<uint16_t> check_types = tmp_entry->GetMergedTypes();
@@ -363,7 +363,7 @@
     }
   }
   RegType* entry = new UnresolvedSuperClass(child.GetId(), this, entries_.size());
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -393,7 +393,7 @@
     }
     entry = new UninitializedReferenceType(klass, descriptor, allocation_pc, entries_.size());
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -435,7 +435,7 @@
       return Conflict();
     }
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -498,7 +498,7 @@
     }
     entry = new UninitializedThisReferenceType(klass, descriptor, entries_.size());
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -517,7 +517,7 @@
   } else {
     entry = new ImpreciseConstType(value, entries_.size());
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -535,7 +535,7 @@
   } else {
     entry = new ImpreciseConstLoType(value, entries_.size());
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -553,7 +553,7 @@
   } else {
     entry = new ImpreciseConstHiType(value, entries_.size());
   }
-  entries_.push_back(entry);
+  AddEntry(entry);
   return *entry;
 }
 
@@ -566,8 +566,15 @@
     return FromDescriptor(loader, component.c_str(), false);
   } else {
     mirror::Class* klass = array.GetClass()->GetComponentType();
-    return FromClass(klass->GetDescriptor().c_str(), klass,
-                     klass->CannotBeAssignedFromOtherTypes());
+    if (klass->IsErroneous()) {
+      // Arrays may have erroneous component types, use unresolved in that case.
+      // We assume that the primitive classes are not erroneous, so we know it is a
+      // reference type.
+      return FromDescriptor(loader, klass->GetDescriptor().c_str(), false);
+    } else {
+      return FromClass(klass->GetDescriptor().c_str(), klass,
+                       klass->CannotBeAssignedFromOtherTypes());
+    }
   }
 }
 
@@ -586,5 +593,9 @@
   }
 }
 
+void RegTypeCache::AddEntry(RegType* new_entry) {
+  entries_.push_back(new_entry);
+}
+
 }  // namespace verifier
 }  // namespace art
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index 70d5f07..f42fdd1 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -154,6 +154,8 @@
   const ConstantType& FromCat1NonSmallConstant(int32_t value, bool precise)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  void AddEntry(RegType* new_entry);
+
   template <class Type>
   static Type* CreatePrimitiveTypeInstance(const std::string& descriptor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 0f8032e..5c1bc03 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -358,6 +358,9 @@
   prereq_rule :=
   skip_test := false
   uc_reloc_type :=
+  ifeq ($(ART_TEST_RUN_TEST_ALWAYS_CLEAN),true)
+    run_test_options += --always-clean
+  endif
   ifeq ($(2),host)
     uc_host_or_target := HOST
     run_test_options += --host
diff --git a/test/run-all-tests b/test/run-all-tests
index 02f46f9..284cca0 100755
--- a/test/run-all-tests
+++ b/test/run-all-tests
@@ -95,6 +95,8 @@
     elif [ "x$1" = "x--prebuild" ]; then
         run_args="${run_args} --prebuild"
         shift;
+    elif [ "x$1" = "x--always-clean" ]; then
+        run_args="${run_args} --always-clean"
     elif expr "x$1" : "x--" >/dev/null 2>&1; then
         echo "unknown $0 option: $1" 1>&2
         usage="yes"
@@ -114,7 +116,7 @@
              "further documentation:"
         echo "    --debug --dev --host --interpreter --jvm --no-optimize"
         echo "    --no-verify -O --update --valgrind --zygote --64 --relocate"
-        echo "    --prebuild"
+        echo "    --prebuild --always-clean"
         echo "  Specific Runtime Options:"
         echo "    --seq                Run tests one-by-one, avoiding failures caused by busy CPU"
     ) 1>&2
diff --git a/test/run-test b/test/run-test
index ae613d9..aef7c52 100755
--- a/test/run-test
+++ b/test/run-test
@@ -73,6 +73,7 @@
 build_only="no"
 suffix64=""
 trace="false"
+always_clean="no"
 
 while true; do
     if [ "x$1" = "x--host" ]; then
@@ -179,6 +180,9 @@
     elif [ "x$1" = "x--trace" ]; then
         trace="true"
         shift
+    elif [ "x$1" = "x--always-clean" ]; then
+        always_clean="yes"
+        shift
     elif expr "x$1" : "x--" >/dev/null 2>&1; then
         echo "unknown $0 option: $1" 1>&2
         usage="yes"
@@ -325,6 +329,7 @@
              "files."
         echo "    --64                 Run the test in 64-bit mode"
         echo "    --trace              Run with method tracing"
+        echo "    --always-clean       Delete the test files even if the test fails."
     ) 1>&2
     exit 1
 fi
@@ -445,19 +450,8 @@
     fi
 fi
 
-# Clean up test files.
-if [ "$good" == "yes" ]; then
-    cd "$oldwd"
-    rm -rf "$tmp_dir"
-    if [ "$target_mode" = "yes" -a "$build_exit" = "0" ]; then
-        adb shell rm -rf $DEX_LOCATION
-    fi
-    exit 0
-fi
-
-
 (
-    if [ "$update_mode" != "yes" ]; then
+    if [ "$good" != "yes" -a "$update_mode" != "yes" ]; then
         echo "${test_dir}: FAILED!"
         echo ' '
         echo '#################### info'
@@ -467,9 +461,33 @@
         echo '####################'
         echo ' '
     fi
-    echo "${TEST_NAME} files left in ${tmp_dir} on host"
-    if [ "$target_mode" == "yes" ]; then
-        echo "and in ${DEX_LOCATION} on target"
+
+) 1>&2
+
+# Clean up test files.
+if [ "$always_clean" = "yes" -o "$good" = "yes" ]; then
+    cd "$oldwd"
+    rm -rf "$tmp_dir"
+    if [ "$target_mode" = "yes" -a "$build_exit" = "0" ]; then
+        adb shell rm -rf $DEX_LOCATION
+    fi
+    if [ "$good" = "yes" ]; then
+        exit 0
+    fi
+fi
+
+
+(
+    if [ "$always_clean" = "yes" ]; then
+        echo "${TEST_NAME} files deleted from host "
+        if [ "$target_mode" == "yes" ]; then
+            echo "and from target"
+        fi
+    else
+        echo "${TEST_NAME} files left in ${tmp_dir} on host"
+        if [ "$target_mode" == "yes" ]; then
+            echo "and in ${DEX_LOCATION} on target"
+        fi
     fi
 
 ) 1>&2