summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk6
-rw-r--r--build/Android.common.mk2
-rw-r--r--runtime/Android.mk1
-rw-r--r--runtime/gc/heap.cc96
-rw-r--r--runtime/gc/heap.h5
-rw-r--r--runtime/object_callbacks.h3
-rw-r--r--runtime/parsed_options.cc16
-rw-r--r--test/Android.mk2
-rwxr-xr-xtest/etc/host-run-test-jar11
-rwxr-xr-xtest/etc/push-and-run-test-jar5
-rwxr-xr-xtest/run-test6
11 files changed, 94 insertions, 59 deletions
diff --git a/Android.mk b/Android.mk
index 5bc57ef9c6..0eaca7f921 100644
--- a/Android.mk
+++ b/Android.mk
@@ -187,14 +187,14 @@ test-art-host-oat: test-art-host-oat-default test-art-host-oat-interpreter
define declare-test-art-host-run-test
.PHONY: test-art-host-run-test-default-$(1)
test-art-host-run-test-default-$(1): test-art-host-dependencies $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
- DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test $(DALVIKVM_FLAGS) --host $(1)
+ DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test $(addprefix --runtime-option ,$(DALVIKVM_FLAGS)) --host $(1)
@echo test-art-host-run-test-default-$(1) PASSED
TEST_ART_HOST_RUN_TEST_DEFAULT_TARGETS += test-art-host-run-test-default-$(1)
.PHONY: test-art-host-run-test-interpreter-$(1)
test-art-host-run-test-interpreter-$(1): test-art-host-dependencies $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
- DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test $(DALVIKVM_FLAGS) --host --interpreter $(1)
+ DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test $(addprefix --runtime-option ,$(DALVIKVM_FLAGS)) --host --interpreter $(1)
@echo test-art-host-run-test-interpreter-$(1) PASSED
TEST_ART_HOST_RUN_TEST_INTERPRETER_TARGETS += test-art-host-run-test-interpreter-$(1)
@@ -266,7 +266,7 @@ ifeq ($($(2)ART_PHONY_TEST_TARGET_SUFFIX),64)
endif
.PHONY: test-art-target-run-test-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
test-art-target-run-test-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-sync $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
- DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test $(DALVIKVM_FLAGS) $$($(2)run_test_$(1)) $(1)
+ DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test $(addprefix --runtime-option ,$(DALVIKVM_FLAGS)) $$($(2)run_test_$(1)) $(1)
@echo test-art-target-run-test-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX) PASSED
endef
diff --git a/build/Android.common.mk b/build/Android.common.mk
index bb17c15e47..3961219d07 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -103,7 +103,7 @@ endif
ifeq ($(ART_USE_OPTIMIZING_COMPILER),true)
DEX2OAT_FLAGS := --compiler-backend=Optimizing
-DALVIKVM_FLAGS := -Xcompiler-option --compiler-backend=Optimizing
+DALVIKVM_FLAGS += -Xcompiler-option --compiler-backend=Optimizing
endif
#
diff --git a/runtime/Android.mk b/runtime/Android.mk
index a64e13730f..1521caa05f 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -297,6 +297,7 @@ LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \
lock_word.h \
mirror/class.h \
oat.h \
+ object_callbacks.h \
quick/inline_method_analyser.h \
thread.h \
thread_state.h \
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 706d1dee60..d37f2ad960 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -1861,39 +1861,54 @@ class ScanVisitor {
// Verify a reference from an object.
class VerifyReferenceVisitor {
public:
- explicit VerifyReferenceVisitor(Heap* heap, bool verify_referent)
+ explicit VerifyReferenceVisitor(Heap* heap, Atomic<size_t>* fail_count, bool verify_referent)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_)
- : heap_(heap), failed_(false), verify_referent_(verify_referent) {}
+ : heap_(heap), fail_count_(fail_count), verify_referent_(verify_referent) {}
- bool Failed() const {
- return failed_;
+ size_t GetFailureCount() const {
+ return fail_count_->Load();
}
void operator()(mirror::Class* klass, mirror::Reference* ref) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
if (verify_referent_) {
- this->operator()(ref, mirror::Reference::ReferentOffset(), false);
+ VerifyReference(ref, ref->GetReferent(), mirror::Reference::ReferentOffset());
}
}
void operator()(mirror::Object* obj, MemberOffset offset, bool /*is_static*/) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- this->operator()(obj, obj->GetFieldObject<mirror::Object>(offset), offset);
+ VerifyReference(obj, obj->GetFieldObject<mirror::Object>(offset), offset);
+ }
+
+ bool IsLive(mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
+ return heap_->IsLiveObjectLocked(obj, true, false, true);
}
+ static void VerifyRootCallback(mirror::Object** root, void* arg, uint32_t thread_id,
+ RootType root_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ VerifyReferenceVisitor* visitor = reinterpret_cast<VerifyReferenceVisitor*>(arg);
+ if (!visitor->VerifyReference(nullptr, *root, MemberOffset(0))) {
+ LOG(ERROR) << "Root " << *root << " is dead with type " << PrettyTypeOf(*root)
+ << " thread_id= " << thread_id << " root_type= " << root_type;
+ }
+ }
+
+ private:
// TODO: Fix the no thread safety analysis.
- void operator()(mirror::Object* obj, mirror::Object* ref, MemberOffset offset) const
+ // Returns false on failure.
+ bool VerifyReference(mirror::Object* obj, mirror::Object* ref, MemberOffset offset) const
NO_THREAD_SAFETY_ANALYSIS {
if (ref == nullptr || IsLive(ref)) {
// Verify that the reference is live.
- return;
+ return true;
}
- if (!failed_) {
+ if (fail_count_->FetchAndAdd(1) == 0) {
// Print message on only on first failure to prevent spam.
LOG(ERROR) << "!!!!!!!!!!!!!!Heap corruption detected!!!!!!!!!!!!!!!!!!!";
- failed_ = true;
}
if (obj != nullptr) {
+ // Only do this part for non roots.
accounting::CardTable* card_table = heap_->GetCardTable();
accounting::ObjectStack* alloc_stack = heap_->allocation_stack_.get();
accounting::ObjectStack* live_stack = heap_->live_stack_.get();
@@ -1972,42 +1987,29 @@ class VerifyReferenceVisitor {
// Search to see if any of the roots reference our reference.
arg = const_cast<void*>(reinterpret_cast<const void*>(ref));
Runtime::Current()->VisitRoots(&RootMatchesObjectVisitor, arg);
- } else {
- LOG(ERROR) << "Root " << ref << " is dead with type " << PrettyTypeOf(ref);
}
+ return false;
}
- bool IsLive(mirror::Object* obj) const NO_THREAD_SAFETY_ANALYSIS {
- return heap_->IsLiveObjectLocked(obj, true, false, true);
- }
-
- static void VerifyRoots(mirror::Object** root, void* arg, uint32_t /*thread_id*/,
- RootType /*root_type*/) {
- VerifyReferenceVisitor* visitor = reinterpret_cast<VerifyReferenceVisitor*>(arg);
- (*visitor)(nullptr, *root, MemberOffset(0));
- }
-
- private:
Heap* const heap_;
- mutable bool failed_;
- bool verify_referent_;
+ Atomic<size_t>* const fail_count_;
+ const bool verify_referent_;
};
// Verify all references within an object, for use with HeapBitmap::Visit.
class VerifyObjectVisitor {
public:
- explicit VerifyObjectVisitor(Heap* heap, bool verify_referent)
- : heap_(heap), failed_(false), verify_referent_(verify_referent) {
+ explicit VerifyObjectVisitor(Heap* heap, Atomic<size_t>* fail_count, bool verify_referent)
+ : heap_(heap), fail_count_(fail_count), verify_referent_(verify_referent) {
}
void operator()(mirror::Object* obj) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_) {
// Note: we are verifying the references in obj but not obj itself, this is because obj must
// be live or else how did we find it in the live bitmap?
- VerifyReferenceVisitor visitor(heap_, verify_referent_);
+ VerifyReferenceVisitor visitor(heap_, fail_count_, verify_referent_);
// The class doesn't count as a reference but we should verify it anyways.
obj->VisitReferences<true>(visitor, visitor);
- failed_ = failed_ || visitor.Failed();
}
static void VisitCallback(mirror::Object* obj, void* arg)
@@ -2016,18 +2018,18 @@ class VerifyObjectVisitor {
visitor->operator()(obj);
}
- bool Failed() const {
- return failed_;
+ size_t GetFailureCount() const {
+ return fail_count_->Load();
}
private:
Heap* const heap_;
- mutable bool failed_;
+ Atomic<size_t>* const fail_count_;
const bool verify_referent_;
};
// Must do this with mutators suspended since we are directly accessing the allocation stacks.
-bool Heap::VerifyHeapReferences(bool verify_referents) {
+size_t Heap::VerifyHeapReferences(bool verify_referents) {
Thread* self = Thread::Current();
Locks::mutator_lock_->AssertExclusiveHeld(self);
// Lets sort our allocation stacks so that we can efficiently binary search them.
@@ -2036,7 +2038,8 @@ bool Heap::VerifyHeapReferences(bool verify_referents) {
// Since we sorted the allocation stack content, need to revoke all
// thread-local allocation stacks.
RevokeAllThreadLocalAllocationStacks(self);
- VerifyObjectVisitor visitor(this, verify_referents);
+ Atomic<size_t> fail_count_(0);
+ VerifyObjectVisitor visitor(this, &fail_count_, verify_referents);
// Verify objects in the allocation stack since these will be objects which were:
// 1. Allocated prior to the GC (pre GC verification).
// 2. Allocated during the GC (pre sweep GC verification).
@@ -2044,8 +2047,8 @@ bool Heap::VerifyHeapReferences(bool verify_referents) {
// pointing to dead objects if they are not reachable.
VisitObjects(VerifyObjectVisitor::VisitCallback, &visitor);
// Verify the roots:
- Runtime::Current()->VisitRoots(VerifyReferenceVisitor::VerifyRoots, &visitor);
- if (visitor.Failed()) {
+ Runtime::Current()->VisitRoots(VerifyReferenceVisitor::VerifyRootCallback, &visitor);
+ if (visitor.GetFailureCount() > 0) {
// Dump mod-union tables.
for (const auto& table_pair : mod_union_tables_) {
accounting::ModUnionTable* mod_union_table = table_pair.second;
@@ -2057,9 +2060,8 @@ bool Heap::VerifyHeapReferences(bool verify_referents) {
remembered_set->Dump(LOG(ERROR) << remembered_set->GetName() << ": ");
}
DumpSpaces();
- return false;
}
- return true;
+ return visitor.GetFailureCount();
}
class VerifyReferenceCardVisitor {
@@ -2262,8 +2264,10 @@ void Heap::PreGcVerificationPaused(collector::GarbageCollector* gc) {
if (verify_pre_gc_heap_) {
TimingLogger::ScopedSplit split("PreGcVerifyHeapReferences", timings);
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
- if (!VerifyHeapReferences()) {
- LOG(FATAL) << "Pre " << gc->GetName() << " heap verification failed";
+ size_t failures = VerifyHeapReferences();
+ if (failures > 0) {
+ LOG(FATAL) << "Pre " << gc->GetName() << " heap verification failed with " << failures
+ << " failures";
}
}
// Check that all objects which reference things in the live stack are on dirty cards.
@@ -2316,8 +2320,10 @@ void Heap::PreSweepingGcVerification(collector::GarbageCollector* gc) {
SwapSemiSpaces();
// Pass in false since concurrent reference processing can mean that the reference referents
// may point to dead objects at the point which PreSweepingGcVerification is called.
- if (!VerifyHeapReferences(false)) {
- LOG(FATAL) << "Pre sweeping " << gc->GetName() << " GC verification failed";
+ size_t failures = VerifyHeapReferences(false);
+ if (failures > 0) {
+ LOG(FATAL) << "Pre sweeping " << gc->GetName() << " GC verification failed with " << failures
+ << " failures";
}
SwapSemiSpaces();
gc->SwapBitmaps();
@@ -2342,8 +2348,10 @@ void Heap::PostGcVerificationPaused(collector::GarbageCollector* gc) {
if (verify_post_gc_heap_) {
TimingLogger::ScopedSplit split("PostGcVerifyHeapReferences", timings);
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
- if (!VerifyHeapReferences()) {
- LOG(FATAL) << "Pre " << gc->GetName() << " heap verification failed";
+ size_t failures = VerifyHeapReferences();
+ if (failures > 0) {
+ LOG(FATAL) << "Pre " << gc->GetName() << " heap verification failed with " << failures
+ << " failures";
}
}
}
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index eea287972e..6fe0dcf24e 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -109,8 +109,6 @@ enum ProcessState {
};
std::ostream& operator<<(std::ostream& os, const ProcessState& process_state);
-std::ostream& operator<<(std::ostream& os, const RootType& root_type);
-
class Heap {
public:
// If true, measure the total allocation time.
@@ -218,7 +216,8 @@ class Heap {
// Check sanity of all live references.
void VerifyHeap() LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
- bool VerifyHeapReferences(bool verify_referents = true)
+ // Returns how many failures occured.
+ size_t VerifyHeapReferences(bool verify_referents = true)
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
bool VerifyMissingCardMarks()
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
diff --git a/runtime/object_callbacks.h b/runtime/object_callbacks.h
index 767c197206..dd8ce16f74 100644
--- a/runtime/object_callbacks.h
+++ b/runtime/object_callbacks.h
@@ -17,6 +17,8 @@
#ifndef ART_RUNTIME_OBJECT_CALLBACKS_H_
#define ART_RUNTIME_OBJECT_CALLBACKS_H_
+// For ostream.
+#include <ostream>
// For uint32_t.
#include <stdint.h>
// For size_t.
@@ -46,6 +48,7 @@ enum RootType {
kRootVMInternal,
kRootJNIMonitor,
};
+std::ostream& operator<<(std::ostream& os, const RootType& root_type);
// Returns the new address of the object, returns root if it has not moved. tid and root_type are
// only used by hprof.
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index f81c25f168..2987393bf2 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -883,11 +883,19 @@ bool ParsedOptions::ParseDouble(const std::string& option, char after_char,
if (!ParseStringAfterChar(option, after_char, &substring)) {
return false;
}
- std::istringstream iss(substring);
+ bool sane_val = true;
double value;
- iss >> value;
- // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range.
- const bool sane_val = iss.eof() && (value >= min) && (value <= max);
+ if (false) {
+ // TODO: this doesn't seem to work on the emulator. b/15114595
+ std::stringstream iss(substring);
+ iss >> value;
+ // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range.
+ sane_val = iss.eof() && (value >= min) && (value <= max);
+ } else {
+ char* end = nullptr;
+ value = strtod(substring.c_str(), &end);
+ sane_val = *end == '\0' && value >= min && value <= max;
+ }
if (!sane_val) {
Usage("Invalid double value %s for option %s\n", substring.c_str(), option.c_str());
return false;
diff --git a/test/Android.mk b/test/Android.mk
index 0684c90564..71f6be16a4 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -153,7 +153,7 @@ test-art-host-oat-interpreter-$(1): $(HOST_OUT_JAVA_LIBRARIES)/$(ART_HOST_ARCH)/
ANDROID_DATA=/tmp/android-data/test-art-host-oat-interpreter-$(1) \
ANDROID_ROOT=$(HOST_OUT) \
LD_LIBRARY_PATH=$(HOST_OUT_SHARED_LIBRARIES) \
- $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd.so -Ximage:$(HOST_CORE_IMG_LOCATION) -Xint -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
+ $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd.so -Ximage:$(HOST_CORE_IMG_LOCATION) $(DALVIKVM_FLAGS) -Xint -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
&& echo test-art-host-oat-interpreter-$(1) PASSED || (echo test-art-host-oat-interpreter-$(1) FAILED && exit 1)
$(hide) rm -r /tmp/android-data/test-art-host-oat-interpreter-$(1)
diff --git a/test/etc/host-run-test-jar b/test/etc/host-run-test-jar
index a844e82bc6..d95559fd5d 100755
--- a/test/etc/host-run-test-jar
+++ b/test/etc/host-run-test-jar
@@ -17,7 +17,7 @@ OPTIMIZE="y"
INVOKE_WITH=""
DEV_MODE="n"
QUIET="n"
-COMPILER_OPTIONS=""
+FLAGS=""
while true; do
if [ "x$1" = "x--quiet" ]; then
@@ -69,7 +69,12 @@ while true; do
elif [ "x$1" = "x-Xcompiler-option" ]; then
shift
option="$1"
- COMPILER_OPTIONS="${COMPILER_OPTIONS} -Xcompiler-option $option"
+ FLAGS="${FLAGS} -Xcompiler-option $option"
+ shift
+ elif [ "x$1" = "x--runtime-option" ]; then
+ shift
+ option="$1"
+ FLAGS="${FLAGS} $option"
shift
elif [ "x$1" = "x--" ]; then
shift
@@ -127,4 +132,4 @@ if [ "$DEV_MODE" = "y" ]; then
fi
cd $ANDROID_BUILD_TOP
-$INVOKE_WITH $gdb $exe $gdbargs -XXlib:$LIB $JNI_OPTS $COMPILER_OPTIONS $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar Main "$@"
+$INVOKE_WITH $gdb $exe $gdbargs -XXlib:$LIB $JNI_OPTS $FLAGS $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar Main "$@"
diff --git a/test/etc/push-and-run-test-jar b/test/etc/push-and-run-test-jar
index 6cf79985a9..b090c339c9 100755
--- a/test/etc/push-and-run-test-jar
+++ b/test/etc/push-and-run-test-jar
@@ -38,6 +38,11 @@ while true; do
option="$1"
FLAGS="${FLAGS} -Xcompiler-option $option"
shift
+ elif [ "x$1" = "x--runtime-option" ]; then
+ shift
+ option="$1"
+ FLAGS="${FLAGS} $option"
+ shift
elif [ "x$1" = "x--boot" ]; then
shift
BOOT_OPT="$1"
diff --git a/test/run-test b/test/run-test
index 323f84665e..34b06cc3a1 100755
--- a/test/run-test
+++ b/test/run-test
@@ -99,6 +99,11 @@ while true; do
option="$1"
run_args="${run_args} -Xcompiler-option $option"
shift
+ elif [ "x$1" = "x--runtime-option" ]; then
+ shift
+ option="$1"
+ run_args="${run_args} --runtime-option $option"
+ shift
elif [ "x$1" = "x--debug" ]; then
run_args="${run_args} --debug"
shift
@@ -234,6 +239,7 @@ if [ "$usage" = "yes" ]; then
echo " Runtime Options:"
echo " -O Run non-debug rather than debug build (off by default)."
echo " -Xcompiler-option Pass an option to the compiler."
+ echo " -runtime-option Pass an option to the runtime."
echo " --debug Wait for a debugger to attach."
echo " --gdb Run under gdb; incompatible with some tests."
echo " --build-only Build test files only (off by default)."