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