diff options
| -rw-r--r-- | build/Android.gtest.mk | 1 | ||||
| -rw-r--r-- | disassembler/disassembler_x86.cc | 16 | ||||
| -rw-r--r-- | patchoat/patchoat.cc | 56 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 10 | ||||
| -rw-r--r-- | runtime/parsed_options.cc | 5 | ||||
| -rw-r--r-- | runtime/runtime.cc | 2 | ||||
| -rw-r--r-- | runtime/runtime.h | 7 | ||||
| -rw-r--r-- | runtime/runtime_common.cc | 3 | ||||
| -rw-r--r-- | runtime/runtime_options.def | 1 | ||||
| -rw-r--r-- | runtime/thread.cc | 12 | ||||
| -rw-r--r-- | runtime/thread.h | 2 | ||||
| -rw-r--r-- | runtime/thread_list.cc | 21 | ||||
| -rw-r--r-- | runtime/thread_list.h | 2 | ||||
| -rw-r--r-- | runtime/verifier/method_verifier.cc | 38 | ||||
| -rw-r--r-- | runtime/verifier/method_verifier.h | 2 | ||||
| -rw-r--r-- | sigchainlib/Android.bp | 4 | ||||
| -rw-r--r-- | sigchainlib/log.h | 45 | ||||
| -rw-r--r-- | sigchainlib/sigchain.cc | 23 | ||||
| -rw-r--r-- | sigchainlib/sigchain_dummy.cc | 21 | ||||
| -rw-r--r-- | test/1934-jvmti-signal-thread/src/art/Test1934.java | 18 | ||||
| -rwxr-xr-x | test/etc/run-test-jar | 4 | ||||
| -rw-r--r-- | test/knownfailures.json | 11 |
22 files changed, 198 insertions, 106 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index e171289410..8681642c0e 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -170,6 +170,7 @@ ART_GTEST_dexoptanalyzer_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_ ART_GTEST_image_space_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ART_GTEST_oat_file_test_DEX_DEPS := Main MultiDex MainUncompressed MultiDexUncompressed ART_GTEST_oat_test_DEX_DEPS := Main +ART_GTEST_oat_writer_test_DEX_DEPS := Main ART_GTEST_object_test_DEX_DEPS := ProtoCompare ProtoCompare2 StaticsFromCode XandY ART_GTEST_patchoat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) ART_GTEST_proxy_test_DEX_DEPS := Interfaces diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc index bbc8e370ea..dbdde647b2 100644 --- a/disassembler/disassembler_x86.cc +++ b/disassembler/disassembler_x86.cc @@ -1194,11 +1194,19 @@ DISASSEMBLER_ENTRY(cmp, opcode1 = opcode_tmp.c_str(); } break; + case 0xD8: + case 0xD9: case 0xDA: + case 0xDC: + case 0xDD: case 0xDE: case 0xE0: case 0xE3: + case 0xE8: + case 0xE9: case 0xEA: + case 0xEC: + case 0xED: case 0xEE: if (prefix[2] == 0x66) { src_reg_file = dst_reg_file = SSE; @@ -1207,11 +1215,19 @@ DISASSEMBLER_ENTRY(cmp, src_reg_file = dst_reg_file = MMX; } switch (*instr) { + case 0xD8: opcode1 = "psubusb"; break; + case 0xD9: opcode1 = "psubusw"; break; case 0xDA: opcode1 = "pminub"; break; + case 0xDC: opcode1 = "paddusb"; break; + case 0xDD: opcode1 = "paddusw"; break; case 0xDE: opcode1 = "pmaxub"; break; case 0xE0: opcode1 = "pavgb"; break; case 0xE3: opcode1 = "pavgw"; break; + case 0xE8: opcode1 = "psubsb"; break; + case 0xE9: opcode1 = "psubsw"; break; case 0xEA: opcode1 = "pminsw"; break; + case 0xEC: opcode1 = "paddsb"; break; + case 0xED: opcode1 = "paddsw"; break; case 0xEE: opcode1 = "pmaxsw"; break; } prefix[2] = 0; diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 3df640902a..b9a9a69ab5 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -65,6 +65,8 @@ namespace art { using android::base::StringPrintf; +namespace { + static const OatHeader* GetOatHeader(const ElfFile* elf_file) { uint64_t off = 0; if (!elf_file->GetSectionOffsetAndSize(".rodata", &off, nullptr)) { @@ -127,6 +129,38 @@ static bool SymlinkFile(const std::string& input_filename, const std::string& ou return true; } +// Holder class for runtime options and related objects. +class PatchoatRuntimeOptionsHolder { + public: + PatchoatRuntimeOptionsHolder(const std::string& image_location, InstructionSet isa) { + options_.push_back(std::make_pair("compilercallbacks", &callbacks_)); + img_ = "-Ximage:" + image_location; + options_.push_back(std::make_pair(img_.c_str(), nullptr)); + isa_name_ = GetInstructionSetString(isa); + options_.push_back(std::make_pair("imageinstructionset", + reinterpret_cast<const void*>(isa_name_.c_str()))); + options_.push_back(std::make_pair("-Xno-sig-chain", nullptr)); + // We do not want the runtime to attempt to patch the image. + options_.push_back(std::make_pair("-Xnorelocate", nullptr)); + // Don't try to compile. + options_.push_back(std::make_pair("-Xnoimage-dex2oat", nullptr)); + // Do not accept broken image. + options_.push_back(std::make_pair("-Xno-dex-file-fallback", nullptr)); + } + + const RuntimeOptions& GetRuntimeOptions() { + return options_; + } + + private: + RuntimeOptions options_; + NoopCompilerCallbacks callbacks_; + std::string isa_name_; + std::string img_; +}; + +} // namespace + bool PatchOat::GeneratePatch( const MemMap& original, const MemMap& relocated, @@ -440,17 +474,10 @@ bool PatchOat::Patch(const std::string& image_location, TimingLogger::ScopedTiming t("Runtime Setup", timings); CHECK_NE(isa, InstructionSet::kNone); - const char* isa_name = GetInstructionSetString(isa); // Set up the runtime - RuntimeOptions options; - NoopCompilerCallbacks callbacks; - options.push_back(std::make_pair("compilercallbacks", &callbacks)); - std::string img = "-Ximage:" + image_location; - options.push_back(std::make_pair(img.c_str(), nullptr)); - options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name))); - options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); - if (!Runtime::Create(options, false)) { + PatchoatRuntimeOptionsHolder options_holder(image_location, isa); + if (!Runtime::Create(options_holder.GetRuntimeOptions(), false)) { LOG(ERROR) << "Unable to initialize runtime"; return false; } @@ -608,17 +635,10 @@ bool PatchOat::Verify(const std::string& image_location, TimingLogger::ScopedTiming t("Runtime Setup", timings); CHECK_NE(isa, InstructionSet::kNone); - const char* isa_name = GetInstructionSetString(isa); // Set up the runtime - RuntimeOptions options; - NoopCompilerCallbacks callbacks; - options.push_back(std::make_pair("compilercallbacks", &callbacks)); - std::string img = "-Ximage:" + image_location; - options.push_back(std::make_pair(img.c_str(), nullptr)); - options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name))); - options.push_back(std::make_pair("-Xno-sig-chain", nullptr)); - if (!Runtime::Create(options, false)) { + PatchoatRuntimeOptionsHolder options_holder(image_location, isa); + if (!Runtime::Create(options_holder.GetRuntimeOptions(), false)) { LOG(ERROR) << "Unable to initialize runtime"; return false; } diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index bf0d3adf0f..72c110a970 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -268,9 +268,13 @@ static void WrapExceptionInInitializer(Handle<mirror::Class> klass) // cannot in general be guaranteed, but in all likelihood leads to breakage down the line. if (klass->GetClassLoader() == nullptr && !Runtime::Current()->IsAotCompiler()) { std::string tmp; - LOG(kIsDebugBuild ? FATAL : WARNING) << klass->GetDescriptor(&tmp) - << " failed initialization: " - << self->GetException()->Dump(); + // We want to LOG(FATAL) on debug builds since this really shouldn't be happening but we need to + // make sure to only do it if we don't have AsyncExceptions being thrown around since those + // could have caused the error. + bool known_impossible = kIsDebugBuild && !Runtime::Current()->AreAsyncExceptionsThrown(); + LOG(known_impossible ? FATAL : WARNING) << klass->GetDescriptor(&tmp) + << " failed initialization: " + << self->GetException()->Dump(); } env->ExceptionClear(); diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index 470287b449..5518eb2c49 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -161,6 +161,10 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize .Define({"-XX:EnableHSpaceCompactForOOM", "-XX:DisableHSpaceCompactForOOM"}) .WithValues({true, false}) .IntoKey(M::EnableHSpaceCompactForOOM) + .Define("-XX:DumpNativeStackOnSigQuit:_") + .WithType<bool>() + .WithValueMap({{"false", false}, {"true", true}}) + .IntoKey(M::DumpNativeStackOnSigQuit) .Define("-XX:MadviseRandomAccess:_") .WithType<bool>() .WithValueMap({{"false", false}, {"true", true}}) @@ -731,6 +735,7 @@ void ParsedOptions::Usage(const char* fmt, ...) { UsageMessage(stream, " -XX:BackgroundGC=none\n"); UsageMessage(stream, " -XX:LargeObjectSpace={disabled,map,freelist}\n"); UsageMessage(stream, " -XX:LargeObjectThreshold=N\n"); + UsageMessage(stream, " -XX:DumpNativeStackOnSigQuit=booleanvalue\n"); UsageMessage(stream, " -XX:MadviseRandomAccess:booleanvalue\n"); UsageMessage(stream, " -XX:SlowDebug={false,true}\n"); UsageMessage(stream, " -Xmethod-trace\n"); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 793d4307b9..7d9d3426fc 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -271,6 +271,7 @@ Runtime::Runtime() pending_hidden_api_warning_(false), dedupe_hidden_api_warnings_(true), always_set_hidden_api_warning_flag_(false), + dump_native_stack_on_sig_quit_(true), pruned_dalvik_cache_(false), // Initially assume we perceive jank in case the process state is never updated. process_state_(kProcessStateJankPerceptible), @@ -1153,6 +1154,7 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { is_explicit_gc_disabled_ = runtime_options.Exists(Opt::DisableExplicitGC); dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::Dex2Oat); image_dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::ImageDex2Oat); + dump_native_stack_on_sig_quit_ = runtime_options.GetOrDefault(Opt::DumpNativeStackOnSigQuit); vfprintf_ = runtime_options.GetOrDefault(Opt::HookVfprintf); exit_ = runtime_options.GetOrDefault(Opt::HookExit); diff --git a/runtime/runtime.h b/runtime/runtime.h index b961e7f39a..c7f650ea3f 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -651,6 +651,10 @@ class Runtime { safe_mode_ = mode; } + bool GetDumpNativeStackOnSigQuit() const { + return dump_native_stack_on_sig_quit_; + } + bool GetPrunedDalvikCache() const { return pruned_dalvik_cache_; } @@ -1001,6 +1005,9 @@ class Runtime { // when there is a warning. This is only used for testing. bool always_set_hidden_api_warning_flag_; + // Whether threads should dump their native stack on SIGQUIT. + bool dump_native_stack_on_sig_quit_; + // Whether the dalvik cache was pruned when initializing the runtime. bool pruned_dalvik_cache_; diff --git a/runtime/runtime_common.cc b/runtime/runtime_common.cc index 41bfb58d93..59af9187f9 100644 --- a/runtime/runtime_common.cc +++ b/runtime/runtime_common.cc @@ -41,6 +41,7 @@ namespace art { using android::base::StringPrintf; static constexpr bool kUseSigRTTimeout = true; +static constexpr bool kDumpNativeStackOnTimeout = true; const char* GetSignalName(int signal_number) { switch (signal_number) { @@ -440,7 +441,7 @@ void HandleUnexpectedSignalCommon(int signal_number, // Special timeout signal. Try to dump all threads. // Note: Do not use DumpForSigQuit, as that might disable native unwind, but the native parts // are of value here. - runtime->GetThreadList()->Dump(std::cerr); + runtime->GetThreadList()->Dump(std::cerr, kDumpNativeStackOnTimeout); std::cerr << std::endl; } diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def index dcb1335023..4121ad69ed 100644 --- a/runtime/runtime_options.def +++ b/runtime/runtime_options.def @@ -70,6 +70,7 @@ RUNTIME_OPTIONS_KEY (Unit, LowMemoryMode) RUNTIME_OPTIONS_KEY (bool, UseTLAB, (kUseTlab || kUseReadBarrier)) RUNTIME_OPTIONS_KEY (bool, EnableHSpaceCompactForOOM, true) RUNTIME_OPTIONS_KEY (bool, UseJitCompilation, false) +RUNTIME_OPTIONS_KEY (bool, DumpNativeStackOnSigQuit, true) RUNTIME_OPTIONS_KEY (bool, MadviseRandomAccess, false) RUNTIME_OPTIONS_KEY (unsigned int, JITCompileThreshold) RUNTIME_OPTIONS_KEY (unsigned int, JITWarmupThreshold) diff --git a/runtime/thread.cc b/runtime/thread.cc index f0bd9aa65e..5b03c2d884 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1161,9 +1161,10 @@ void Thread::ShortDump(std::ostream& os) const { << "]"; } -void Thread::Dump(std::ostream& os, BacktraceMap* backtrace_map, bool force_dump_stack) const { +void Thread::Dump(std::ostream& os, bool dump_native_stack, BacktraceMap* backtrace_map, + bool force_dump_stack) const { DumpState(os); - DumpStack(os, backtrace_map, force_dump_stack); + DumpStack(os, dump_native_stack, backtrace_map, force_dump_stack); } mirror::String* Thread::GetThreadName() const { @@ -1963,7 +1964,10 @@ void Thread::DumpJavaStack(std::ostream& os, bool check_suspended, bool dump_loc } } -void Thread::DumpStack(std::ostream& os, BacktraceMap* backtrace_map, bool force_dump_stack) const { +void Thread::DumpStack(std::ostream& os, + bool dump_native_stack, + BacktraceMap* backtrace_map, + bool force_dump_stack) const { // TODO: we call this code when dying but may not have suspended the thread ourself. The // IsSuspended check is therefore racy with the use for dumping (normally we inhibit // the race with the thread_suspend_count_lock_). @@ -1976,7 +1980,7 @@ void Thread::DumpStack(std::ostream& os, BacktraceMap* backtrace_map, bool force } if (safe_to_dump || force_dump_stack) { // If we're currently in native code, dump that stack before dumping the managed stack. - if (dump_for_abort || force_dump_stack || ShouldShowNativeStack(this)) { + if (dump_native_stack && (dump_for_abort || force_dump_stack || ShouldShowNativeStack(this))) { DumpKernelStack(os, GetTid(), " kernel: ", false); ArtMethod* method = GetCurrentMethod(nullptr, diff --git a/runtime/thread.h b/runtime/thread.h index 108fbc7f86..6549fc1a1f 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -207,6 +207,7 @@ class Thread { // Dumps the detailed thread state and the thread stack (used for SIGQUIT). void Dump(std::ostream& os, + bool dump_native_stack = true, BacktraceMap* backtrace_map = nullptr, bool force_dump_stack = false) const REQUIRES(!Locks::thread_suspend_count_lock_) @@ -1302,6 +1303,7 @@ class Thread { void DumpState(std::ostream& os) const REQUIRES_SHARED(Locks::mutator_lock_); void DumpStack(std::ostream& os, + bool dump_native_stack = true, BacktraceMap* backtrace_map = nullptr, bool force_dump_stack = false) const REQUIRES(!Locks::thread_suspend_count_lock_) diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index 2e41b9f455..8095ef57c7 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -152,8 +152,9 @@ void ThreadList::DumpForSigQuit(std::ostream& os) { suspend_all_historam_.PrintConfidenceIntervals(os, 0.99, data); // Dump time to suspend. } } - Dump(os); - DumpUnattachedThreads(os, kDumpUnattachedThreadNativeStackForSigQuit); + bool dump_native_stack = Runtime::Current()->GetDumpNativeStackOnSigQuit(); + Dump(os, dump_native_stack); + DumpUnattachedThreads(os, dump_native_stack && kDumpUnattachedThreadNativeStackForSigQuit); } static void DumpUnattachedThread(std::ostream& os, pid_t tid, bool dump_native_stack) @@ -200,10 +201,11 @@ static constexpr uint32_t kDumpWaitTimeout = kIsTargetBuild ? 100000 : 20000; // A closure used by Thread::Dump. class DumpCheckpoint FINAL : public Closure { public: - explicit DumpCheckpoint(std::ostream* os) + DumpCheckpoint(std::ostream* os, bool dump_native_stack) : os_(os), barrier_(0), - backtrace_map_(BacktraceMap::Create(getpid())) { + backtrace_map_(dump_native_stack ? BacktraceMap::Create(getpid()) : nullptr), + dump_native_stack_(dump_native_stack) { if (backtrace_map_ != nullptr) { backtrace_map_->SetSuffixesToIgnore(std::vector<std::string> { "oat", "odex" }); } @@ -217,7 +219,7 @@ class DumpCheckpoint FINAL : public Closure { std::ostringstream local_os; { ScopedObjectAccess soa(self); - thread->Dump(local_os, backtrace_map_.get()); + thread->Dump(local_os, dump_native_stack_, backtrace_map_.get()); } { // Use the logging lock to ensure serialization when writing to the common ostream. @@ -245,16 +247,18 @@ class DumpCheckpoint FINAL : public Closure { Barrier barrier_; // A backtrace map, so that all threads use a shared info and don't reacquire/parse separately. std::unique_ptr<BacktraceMap> backtrace_map_; + // Whether we should dump the native stack. + const bool dump_native_stack_; }; -void ThreadList::Dump(std::ostream& os) { +void ThreadList::Dump(std::ostream& os, bool dump_native_stack) { Thread* self = Thread::Current(); { MutexLock mu(self, *Locks::thread_list_lock_); os << "DALVIK THREADS (" << list_.size() << "):\n"; } if (self != nullptr) { - DumpCheckpoint checkpoint(&os); + DumpCheckpoint checkpoint(&os, dump_native_stack); size_t threads_running_checkpoint; { // Use SOA to prevent deadlocks if multiple threads are calling Dump() at the same time. @@ -265,7 +269,7 @@ void ThreadList::Dump(std::ostream& os) { checkpoint.WaitForThreadsToRunThroughCheckpoint(threads_running_checkpoint); } } else { - DumpUnattachedThreads(os, /* dump_native_stack */ true); + DumpUnattachedThreads(os, dump_native_stack); } } @@ -487,6 +491,7 @@ void ThreadList::RunEmptyCheckpoint() { // Found a runnable thread that hasn't responded to the empty checkpoint request. // Assume it's stuck and safe to dump its stack. thread->Dump(LOG_STREAM(FATAL_WITHOUT_ABORT), + /*dump_native_stack*/ true, /*backtrace_map*/ nullptr, /*force_dump_stack*/ true); } diff --git a/runtime/thread_list.h b/runtime/thread_list.h index 09b10d2ad3..895c1a41ce 100644 --- a/runtime/thread_list.h +++ b/runtime/thread_list.h @@ -57,7 +57,7 @@ class ThreadList { void DumpForSigQuit(std::ostream& os) REQUIRES(!Locks::thread_list_lock_, !Locks::mutator_lock_); // For thread suspend timeout dumps. - void Dump(std::ostream& os) + void Dump(std::ostream& os, bool dump_native_stack = true) REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_); pid_t GetLockOwner(); // For SignalCatcher. diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 21a4ecca47..2a2afc4a27 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -105,25 +105,27 @@ void PcToRegisterLineTable::Init(RegisterTrackingMode mode, InstructionFlags* fl PcToRegisterLineTable::~PcToRegisterLineTable() {} // Note: returns true on failure. -ALWAYS_INLINE static inline bool FailOrAbort(MethodVerifier* verifier, bool condition, - const char* error_msg, uint32_t work_insn_idx) { +inline bool MethodVerifier::FailOrAbort(bool condition, + const char* error_msg, + uint32_t work_insn_idx) { if (kIsDebugBuild) { // In a debug build, abort if the error condition is wrong. Only warn if // we are already aborting (as this verification is likely run to print // lock information). if (LIKELY(gAborting == 0)) { - DCHECK(condition) << error_msg << work_insn_idx; + DCHECK(condition) << error_msg << work_insn_idx << " " + << dex_file_->PrettyMethod(dex_method_idx_); } else { if (!condition) { LOG(ERROR) << error_msg << work_insn_idx; - verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << error_msg << work_insn_idx; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << error_msg << work_insn_idx; return true; } } } else { // In a non-debug build, just fail the class. if (!condition) { - verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << error_msg << work_insn_idx; + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << error_msg << work_insn_idx; return true; } } @@ -2683,7 +2685,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { while (0 != instance_of_idx && !GetInstructionFlags(instance_of_idx).IsOpcode()) { instance_of_idx--; } - if (FailOrAbort(this, GetInstructionFlags(instance_of_idx).IsOpcode(), + if (FailOrAbort(GetInstructionFlags(instance_of_idx).IsOpcode(), "Unable to get previous instruction of if-eqz/if-nez for work index ", work_insn_idx_)) { break; @@ -2750,7 +2752,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { while (0 != move_idx && !GetInstructionFlags(move_idx).IsOpcode()) { move_idx--; } - if (FailOrAbort(this, GetInstructionFlags(move_idx).IsOpcode(), + if (FailOrAbort(GetInstructionFlags(move_idx).IsOpcode(), "Unable to get previous instruction of if-eqz/if-nez for work index ", work_insn_idx_)) { break; @@ -3863,8 +3865,7 @@ const RegType& MethodVerifier::GetCaughtExceptionType() { // odd case, but nothing to do } else { common_super = &common_super->Merge(exception, ®_types_, this); - if (FailOrAbort(this, - reg_types_.JavaLangThrowable(false).IsAssignableFrom( + if (FailOrAbort(reg_types_.JavaLangThrowable(false).IsAssignableFrom( *common_super, this), "java.lang.Throwable is not assignable-from common_super at ", work_insn_idx_)) { @@ -4430,8 +4431,9 @@ ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst, Regist if (klass->IsInterface()) { // Derive Object.class from Class.class.getSuperclass(). mirror::Class* object_klass = klass->GetClass()->GetSuperClass(); - if (FailOrAbort(this, object_klass->IsObjectClass(), - "Failed to find Object class in quickened invoke receiver", work_insn_idx_)) { + if (FailOrAbort(object_klass->IsObjectClass(), + "Failed to find Object class in quickened invoke receiver", + work_insn_idx_)) { return nullptr; } dispatch_class = object_klass; @@ -4439,7 +4441,8 @@ ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst, Regist dispatch_class = klass; } if (!dispatch_class->HasVTable()) { - FailOrAbort(this, allow_failure, "Receiver class has no vtable for quickened invoke at ", + FailOrAbort(allow_failure, + "Receiver class has no vtable for quickened invoke at ", work_insn_idx_); return nullptr; } @@ -4447,14 +4450,15 @@ ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst, Regist auto* cl = Runtime::Current()->GetClassLinker(); auto pointer_size = cl->GetImagePointerSize(); if (static_cast<int32_t>(vtable_index) >= dispatch_class->GetVTableLength()) { - FailOrAbort(this, allow_failure, + FailOrAbort(allow_failure, "Receiver class has not enough vtable slots for quickened invoke at ", work_insn_idx_); return nullptr; } ArtMethod* res_method = dispatch_class->GetVTableEntry(vtable_index, pointer_size); if (self_->IsExceptionPending()) { - FailOrAbort(this, allow_failure, "Unexpected exception pending for quickened invoke at ", + FailOrAbort(allow_failure, + "Unexpected exception pending for quickened invoke at ", work_insn_idx_); return nullptr; } @@ -4470,11 +4474,13 @@ ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst, Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer method from " << inst->Name(); return nullptr; } - if (FailOrAbort(this, !res_method->IsDirect(), "Quick-invoked method is direct at ", + if (FailOrAbort(!res_method->IsDirect(), + "Quick-invoked method is direct at ", work_insn_idx_)) { return nullptr; } - if (FailOrAbort(this, !res_method->IsStatic(), "Quick-invoked method is static at ", + if (FailOrAbort(!res_method->IsStatic(), + "Quick-invoked method is static at ", work_insn_idx_)) { return nullptr; } diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 26c598f224..9a94297942 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -721,6 +721,8 @@ class MethodVerifier { const RegType& FromClass(const char* descriptor, mirror::Class* klass, bool precise) REQUIRES_SHARED(Locks::mutator_lock_); + ALWAYS_INLINE bool FailOrAbort(bool condition, const char* error_msg, uint32_t work_insn_idx); + // The thread we're verifying on. Thread* const self_; diff --git a/sigchainlib/Android.bp b/sigchainlib/Android.bp index 1f490cd3b9..a151d7a6bc 100644 --- a/sigchainlib/Android.bp +++ b/sigchainlib/Android.bp @@ -35,7 +35,7 @@ cc_library { }, android: { - shared_libs: ["liblog"], + whole_static_libs: ["libasync_safe"], }, }, // Sigchainlib is whole-statically linked into binaries. For Android.mk-based binaries, @@ -56,7 +56,7 @@ cc_library_static { srcs: ["sigchain_dummy.cc"], target: { android: { - shared_libs: ["liblog"], + whole_static_libs: ["libasync_safe"], }, }, } diff --git a/sigchainlib/log.h b/sigchainlib/log.h new file mode 100644 index 0000000000..d689930c1e --- /dev/null +++ b/sigchainlib/log.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_SIGCHAINLIB_LOG_H_ +#define ART_SIGCHAINLIB_LOG_H_ + +#if defined(__ANDROID__) + +#include <async_safe/log.h> + +#define log(...) async_safe_format_log(ANDROID_LOG_ERROR, "libsigchain", __VA_ARGS__) +#define fatal async_safe_fatal + +#else + +#include <stdarg.h> +#include <stdio.h> + +static void log(const char* format, ...) { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + + printf("\n"); +} + +#define fatal(...) log(__VA_ARGS__); abort() + +#endif + +#endif // ART_SIGCHAINLIB_LOG_H_ diff --git a/sigchainlib/sigchain.cc b/sigchainlib/sigchain.cc index 3127c5cfbd..2e5f46ca69 100644 --- a/sigchainlib/sigchain.cc +++ b/sigchainlib/sigchain.cc @@ -14,13 +14,6 @@ * limitations under the License. */ -#ifdef ART_TARGET_ANDROID -#include <android/log.h> -#else -#include <stdarg.h> -#include <iostream> -#endif - #include <dlfcn.h> #include <errno.h> #include <pthread.h> @@ -35,6 +28,7 @@ #include <type_traits> #include <utility> +#include "log.h" #include "sigchain.h" #if defined(__APPLE__) @@ -65,21 +59,6 @@ // doesn't have SA_RESTART, and raise the signal to avoid restarting syscalls that are // expected to be interrupted? -static void log(const char* format, ...) { - char buf[256]; - va_list ap; - va_start(ap, format); - vsnprintf(buf, sizeof(buf), format, ap); -#ifdef ART_TARGET_ANDROID - __android_log_write(ANDROID_LOG_ERROR, "libsigchain", buf); -#else - std::cout << buf << "\n"; -#endif - va_end(ap); -} - -#define fatal(...) log(__VA_ARGS__); abort() - #if defined(__BIONIC__) && !defined(__LP64__) && !defined(__mips__) static int sigismember(const sigset64_t* sigset, int signum) { return sigismember64(sigset, signum); diff --git a/sigchainlib/sigchain_dummy.cc b/sigchainlib/sigchain_dummy.cc index edce965e33..c274530987 100644 --- a/sigchainlib/sigchain_dummy.cc +++ b/sigchainlib/sigchain_dummy.cc @@ -17,13 +17,7 @@ #include <stdio.h> #include <stdlib.h> -#ifdef ART_TARGET_ANDROID -#include <android/log.h> -#else -#include <stdarg.h> -#include <iostream> -#endif - +#include "log.h" #include "sigchain.h" #define ATTRIBUTE_UNUSED __attribute__((__unused__)) @@ -33,19 +27,6 @@ #pragma GCC diagnostic ignored "-Wunknown-pragmas" #pragma GCC diagnostic ignored "-Wmissing-noreturn" -static void log(const char* format, ...) { - char buf[256]; - va_list ap; - va_start(ap, format); - vsnprintf(buf, sizeof(buf), format, ap); -#ifdef ART_TARGET_ANDROID - __android_log_write(ANDROID_LOG_ERROR, "libsigchain", buf); -#else - std::cout << buf << "\n"; -#endif - va_end(ap); -} - namespace art { extern "C" void EnsureFrontOfChain(int signal ATTRIBUTE_UNUSED) { diff --git a/test/1934-jvmti-signal-thread/src/art/Test1934.java b/test/1934-jvmti-signal-thread/src/art/Test1934.java index 2a3f8db5f8..308f17b961 100644 --- a/test/1934-jvmti-signal-thread/src/art/Test1934.java +++ b/test/1934-jvmti-signal-thread/src/art/Test1934.java @@ -25,6 +25,8 @@ public class Test1934 { public static final boolean PRINT_STACK_TRACE = false; public static void run() throws Exception { + ensureClassesLoaded(); + System.out.println("Interrupt before start"); testInterruptBeforeStart(); @@ -53,6 +55,22 @@ public class Test1934 { testStopInNative(); } + private static void ensureInitialized(Class c) { + try { + Class.forName(c.getName()); + } catch (Exception e) { + throw new Error("Failed to initialize " + c, e); + } + } + + private static void ensureClassesLoaded() { + // Depending on timing this class might (or might not) be loaded during testing of Stop. If it + // is and the StopThread occurs inside of it we will get a ExceptionInInitializerError which is + // not what we are looking for. In order to avoid this ever happening simply initialize the + // class that can cause it early. + ensureInitialized(java.util.concurrent.locks.LockSupport.class); + } + public static void testStopBeforeStart() throws Exception { final Throwable[] out_err = new Throwable[] { null, }; final Object tst = new Object(); diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index 86adb733a9..e9127a8101 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -775,6 +775,9 @@ if [ "$HOST" = "n" ]; then TMP_DIR_OPTION="-Djava.io.tmpdir=/data/local/tmp" fi +# We set DumpNativeStackOnSigQuit to false to avoid stressing libunwind. +# b/27185632 +# b/24664297 dalvikvm_cmdline="$INVOKE_WITH $GDB $ANDROID_ROOT/bin/$DALVIKVM \ $GDB_ARGS \ $FLAGS \ @@ -789,6 +792,7 @@ dalvikvm_cmdline="$INVOKE_WITH $GDB $ANDROID_ROOT/bin/$DALVIKVM \ $DEBUGGER_OPTS \ $DALVIKVM_BOOT_OPT \ $TMP_DIR_OPTION \ + -XX:DumpNativeStackOnSigQuit:false \ -cp $DEX_LOCATION/$TEST_NAME.jar$SECONDARY_DEX $MAIN $ARGS" # Remove whitespace. diff --git a/test/knownfailures.json b/test/knownfailures.json index b2f579d3b9..d1855dcbc7 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -286,11 +286,6 @@ "variant": "npictest" }, { - "tests": "639-checker-code-sinking", - "variant": "pictest", - "bug": "http://b/65366606" - }, - { "tests": "055-enum-performance", "variant": "optimizing | regalloc_gc", "description": ["055: Exceeds run time limits due to heap poisoning ", @@ -670,12 +665,6 @@ "description": ["Time out"] }, { - "tests": ["130-hprof"], - "env_vars": {"SANITIZE_HOST": "address"}, - "bug": "b/73060923", - "description": ["ASAN issue"] - }, - { "tests": ["1941-dispose-stress", "522-checker-regression-monitor-exit"], "variant": "jvm", "bug": "b/73888836", |