summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/Android.gtest.mk1
-rw-r--r--disassembler/disassembler_x86.cc16
-rw-r--r--patchoat/patchoat.cc56
-rw-r--r--runtime/class_linker.cc10
-rw-r--r--runtime/parsed_options.cc5
-rw-r--r--runtime/runtime.cc2
-rw-r--r--runtime/runtime.h7
-rw-r--r--runtime/runtime_common.cc3
-rw-r--r--runtime/runtime_options.def1
-rw-r--r--runtime/thread.cc12
-rw-r--r--runtime/thread.h2
-rw-r--r--runtime/thread_list.cc21
-rw-r--r--runtime/thread_list.h2
-rw-r--r--runtime/verifier/method_verifier.cc38
-rw-r--r--runtime/verifier/method_verifier.h2
-rw-r--r--sigchainlib/Android.bp4
-rw-r--r--sigchainlib/log.h45
-rw-r--r--sigchainlib/sigchain.cc23
-rw-r--r--sigchainlib/sigchain_dummy.cc21
-rw-r--r--test/1934-jvmti-signal-thread/src/art/Test1934.java18
-rwxr-xr-xtest/etc/run-test-jar4
-rw-r--r--test/knownfailures.json11
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, &reg_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",