diff options
| -rw-r--r-- | Android.mk | 6 | ||||
| -rw-r--r-- | build/Android.common.mk | 2 | ||||
| -rw-r--r-- | runtime/Android.mk | 1 | ||||
| -rw-r--r-- | runtime/gc/heap.cc | 96 | ||||
| -rw-r--r-- | runtime/gc/heap.h | 5 | ||||
| -rw-r--r-- | runtime/object_callbacks.h | 3 | ||||
| -rw-r--r-- | runtime/parsed_options.cc | 16 | ||||
| -rw-r--r-- | test/Android.mk | 2 | ||||
| -rwxr-xr-x | test/etc/host-run-test-jar | 11 | ||||
| -rwxr-xr-x | test/etc/push-and-run-test-jar | 5 | ||||
| -rwxr-xr-x | test/run-test | 6 |
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)." |