Merge "Add basic support for object pointer poisoning"
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
index 617f5b0..a7ca279 100644
--- a/benchmark/Android.bp
+++ b/benchmark/Android.bp
@@ -26,6 +26,7 @@
shared_libs: [
"libart",
"libbacktrace",
+ "libbase",
"libnativehelper",
],
clang: true,
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 09c53b6..f264d30 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -185,6 +185,7 @@
},
generated_sources: ["art_compiler_operator_srcs"],
shared_libs: [
+ "libbase",
"liblz4",
"liblzma",
],
@@ -288,6 +289,7 @@
shared_libs: [
"libartd-compiler",
"libart-runtime-gtest",
+ "libbase",
],
}
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 8d53dbf..6750554 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -640,28 +640,6 @@
INTRINSIC(JavaLangLong, RotateLeft, JI_J, kIntrinsicRotateLeft, k64),
#undef INTRINSIC
-
-#define SPECIAL(c, n, p, o, d) \
- { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineSpecial, { d } } }
-
- SPECIAL(JavaLangString, Init, _V, kInlineStringInit, 0),
- SPECIAL(JavaLangString, Init, ByteArray_V, kInlineStringInit, 1),
- SPECIAL(JavaLangString, Init, ByteArrayI_V, kInlineStringInit, 2),
- SPECIAL(JavaLangString, Init, ByteArrayII_V, kInlineStringInit, 3),
- SPECIAL(JavaLangString, Init, ByteArrayIII_V, kInlineStringInit, 4),
- SPECIAL(JavaLangString, Init, ByteArrayIIString_V, kInlineStringInit, 5),
- SPECIAL(JavaLangString, Init, ByteArrayString_V, kInlineStringInit, 6),
- SPECIAL(JavaLangString, Init, ByteArrayIICharset_V, kInlineStringInit, 7),
- SPECIAL(JavaLangString, Init, ByteArrayCharset_V, kInlineStringInit, 8),
- SPECIAL(JavaLangString, Init, CharArray_V, kInlineStringInit, 9),
- SPECIAL(JavaLangString, Init, CharArrayII_V, kInlineStringInit, 10),
- SPECIAL(JavaLangString, Init, IICharArray_V, kInlineStringInit, 11),
- SPECIAL(JavaLangString, Init, IntArrayII_V, kInlineStringInit, 12),
- SPECIAL(JavaLangString, Init, String_V, kInlineStringInit, 13),
- SPECIAL(JavaLangString, Init, StringBuffer_V, kInlineStringInit, 14),
- SPECIAL(JavaLangString, Init, StringBuilder_V, kInlineStringInit, 15),
-
-#undef SPECIAL
};
DexFileMethodInliner::DexFileMethodInliner()
@@ -843,22 +821,4 @@
}
}
-uint32_t DexFileMethodInliner::GetOffsetForStringInit(uint32_t method_index,
- PointerSize pointer_size) {
- ReaderMutexLock mu(Thread::Current(), lock_);
- auto it = inline_methods_.find(method_index);
- if (it != inline_methods_.end() && (it->second.opcode == kInlineStringInit)) {
- uint32_t string_init_base_offset = Thread::QuickEntryPointOffsetWithSize(
- OFFSETOF_MEMBER(QuickEntryPoints, pNewEmptyString), pointer_size);
- return string_init_base_offset + it->second.d.data * static_cast<size_t>(pointer_size);
- }
- return 0;
-}
-
-bool DexFileMethodInliner::IsStringInitMethodIndex(uint32_t method_index) {
- ReaderMutexLock mu(Thread::Current(), lock_);
- auto it = inline_methods_.find(method_index);
- return (it != inline_methods_.end()) && (it->second.opcode == kInlineStringInit);
-}
-
} // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index 43fc687..f4ae5a5 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -82,17 +82,6 @@
bool IsSpecial(uint32_t method_index) REQUIRES(!lock_);
/**
- * Gets the thread pointer entrypoint offset for a string init method index and pointer size.
- */
- uint32_t GetOffsetForStringInit(uint32_t method_index, PointerSize pointer_size)
- REQUIRES(!lock_);
-
- /**
- * Check whether a particular method index is a string init.
- */
- bool IsStringInitMethodIndex(uint32_t method_index) REQUIRES(!lock_);
-
- /**
* To avoid multiple lookups of a class by its descriptor, we cache its
* type index in the IndexCache. These are the indexes into the IndexCache
* class_indexes array.
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index adbf9fd..f1d3116 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -595,9 +595,14 @@
: optimizer::DexToDexCompilationLevel::kRequired);
}
} else if ((access_flags & kAccNative) != 0) {
- // Are we extracting only and have support for generic JNI down calls?
- if (!driver->GetCompilerOptions().IsJniCompilationEnabled() &&
- InstructionSetHasGenericJniStub(driver->GetInstructionSet())) {
+ const InstructionSet instruction_set = driver->GetInstructionSet();
+ const bool use_generic_jni =
+ // Are we extracting only and have support for generic JNI down calls?
+ (!driver->GetCompilerOptions().IsJniCompilationEnabled() &&
+ InstructionSetHasGenericJniStub(instruction_set)) ||
+ // Always punt to generic JNI for MIPS because of no support for @CriticalNative. b/31743474
+ (instruction_set == kMips || instruction_set == kMips64);
+ if (use_generic_jni) {
// Leaving this empty will trigger the generic JNI version
} else {
// Look-up the ArtMethod associated with this code_item (if any)
@@ -2789,18 +2794,6 @@
return oss.str();
}
-bool CompilerDriver::IsStringTypeIndex(uint16_t type_index, const DexFile* dex_file) {
- const char* type = dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_index));
- return strcmp(type, "Ljava/lang/String;") == 0;
-}
-
-bool CompilerDriver::IsStringInit(uint32_t method_index, const DexFile* dex_file, int32_t* offset) {
- DexFileMethodInliner* inliner = GetMethodInlinerMap()->GetMethodInliner(dex_file);
- const PointerSize pointer_size = InstructionSetPointerSize(GetInstructionSet());
- *offset = inliner->GetOffsetForStringInit(method_index, pointer_size);
- return inliner->IsStringInitMethodIndex(method_index);
-}
-
bool CompilerDriver::MayInlineInternal(const DexFile* inlined_from,
const DexFile* inlined_into) const {
// We're not allowed to inline across dex files if we're the no-inline-from dex file.
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 1f4c3ac..41f0d36 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -432,9 +432,6 @@
// Get memory usage during compilation.
std::string GetMemoryUsageString(bool extended) const;
- bool IsStringTypeIndex(uint16_t type_index, const DexFile* dex_file);
- bool IsStringInit(uint32_t method_index, const DexFile* dex_file, int32_t* offset);
-
void SetHadHardVerifierFailure() {
had_hard_verifier_failure_ = true;
}
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 9045817..c840a9e 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -966,7 +966,7 @@
nullptr,
invoke_type);
if (method == nullptr) {
- LOG(INTERNAL_FATAL) << "Unexpected failure to resolve a method: "
+ LOG(FATAL_WITHOUT_ABORT) << "Unexpected failure to resolve a method: "
<< PrettyMethod(it.GetMemberIndex(), *dex_file_, true);
soa.Self()->AssertPendingException();
mirror::Throwable* exc = soa.Self()->GetException();
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 6be458c..55e1221 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -6748,10 +6748,13 @@
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
+ uint32_t offset =
+ GetThreadOffset<kArmPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
// temp = thread->string_init_entrypoint
- __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, invoke->GetStringInitOffset());
+ __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), TR, offset);
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 7160607..a2a2e42 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -3570,10 +3570,13 @@
// Make sure that ArtMethod* is passed in kArtMethodRegister as per the calling convention.
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
+ uint32_t offset =
+ GetThreadOffset<kArm64PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
// temp = thread->string_init_entrypoint
- __ Ldr(XRegisterFrom(temp), MemOperand(tr, invoke->GetStringInitOffset()));
+ __ Ldr(XRegisterFrom(temp), MemOperand(tr, offset));
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index f560207..5c0ca85 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -4396,13 +4396,16 @@
}
switch (method_load_kind) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
// temp = thread->string_init_entrypoint
+ uint32_t offset =
+ GetThreadOffset<kMipsPointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
__ LoadFromOffset(kLoadWord,
temp.AsRegister<Register>(),
TR,
- invoke->GetStringInitOffset());
+ offset);
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index a5e2351..02576bd 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3006,13 +3006,16 @@
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
// temp = thread->string_init_entrypoint
+ uint32_t offset =
+ GetThreadOffset<kMips64PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
__ LoadFromOffset(kLoadDoubleword,
temp.AsRegister<GpuRegister>(),
TR,
- invoke->GetStringInitOffset());
+ offset);
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 47dfb2e..c300080 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4276,10 +4276,13 @@
Location temp) {
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
// temp = thread->string_init_entrypoint
- __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(invoke->GetStringInitOffset()));
+ uint32_t offset =
+ GetThreadOffset<kX86PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
+ __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(offset));
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 59c0ca4..f9a3e42 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -754,11 +754,13 @@
// All registers are assumed to be correctly set up.
Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
switch (invoke->GetMethodLoadKind()) {
- case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
+ case HInvokeStaticOrDirect::MethodLoadKind::kStringInit: {
// temp = thread->string_init_entrypoint
- __ gs()->movq(temp.AsRegister<CpuRegister>(),
- Address::Absolute(invoke->GetStringInitOffset(), /* no_rip */ true));
+ uint32_t offset =
+ GetThreadOffset<kX86_64PointerSize>(invoke->GetStringInitEntryPoint()).Int32Value();
+ __ gs()->movq(temp.AsRegister<CpuRegister>(), Address::Absolute(offset, /* no_rip */ true));
break;
+ }
case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
callee_method = invoke->GetLocations()->InAt(invoke->GetSpecialInputIndex());
break;
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index f7dc237..139daa7 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -767,6 +767,11 @@
return resolved_method;
}
+static bool IsStringConstructor(ArtMethod* method) {
+ ScopedObjectAccess soa(Thread::Current());
+ return method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
+}
+
bool HInstructionBuilder::BuildInvoke(const Instruction& instruction,
uint32_t dex_pc,
uint32_t method_idx,
@@ -785,39 +790,6 @@
number_of_arguments++;
}
- // Special handling for string init.
- int32_t string_init_offset = 0;
- bool is_string_init = compiler_driver_->IsStringInit(method_idx,
- dex_file_,
- &string_init_offset);
- // Replace calls to String.<init> with StringFactory.
- if (is_string_init) {
- HInvokeStaticOrDirect::DispatchInfo dispatch_info = {
- HInvokeStaticOrDirect::MethodLoadKind::kStringInit,
- HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
- dchecked_integral_cast<uint64_t>(string_init_offset),
- 0U
- };
- MethodReference target_method(dex_file_, method_idx);
- HInvoke* invoke = new (arena_) HInvokeStaticOrDirect(
- arena_,
- number_of_arguments - 1,
- Primitive::kPrimNot /*return_type */,
- dex_pc,
- method_idx,
- nullptr,
- dispatch_info,
- invoke_type,
- target_method,
- HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit);
- return HandleStringInit(invoke,
- number_of_vreg_arguments,
- args,
- register_index,
- is_range,
- descriptor);
- }
-
ArtMethod* resolved_method = ResolveMethod(method_idx, invoke_type);
if (UNLIKELY(resolved_method == nullptr)) {
@@ -838,6 +810,35 @@
true /* is_unresolved */);
}
+ // Replace calls to String.<init> with StringFactory.
+ if (IsStringConstructor(resolved_method)) {
+ uint32_t string_init_entry_point = WellKnownClasses::StringInitToEntryPoint(resolved_method);
+ HInvokeStaticOrDirect::DispatchInfo dispatch_info = {
+ HInvokeStaticOrDirect::MethodLoadKind::kStringInit,
+ HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod,
+ dchecked_integral_cast<uint64_t>(string_init_entry_point),
+ 0U
+ };
+ MethodReference target_method(dex_file_, method_idx);
+ HInvoke* invoke = new (arena_) HInvokeStaticOrDirect(
+ arena_,
+ number_of_arguments - 1,
+ Primitive::kPrimNot /*return_type */,
+ dex_pc,
+ method_idx,
+ nullptr,
+ dispatch_info,
+ invoke_type,
+ target_method,
+ HInvokeStaticOrDirect::ClinitCheckRequirement::kImplicit);
+ return HandleStringInit(invoke,
+ number_of_vreg_arguments,
+ args,
+ register_index,
+ is_range,
+ descriptor);
+ }
+
// Potential class initialization check, in the case of a static method call.
HClinitCheck* clinit_check = nullptr;
HInvoke* invoke = nullptr;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 57ae555..4dc4c20 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -4044,9 +4044,9 @@
}
bool HasDirectCodePtr() const { return GetCodePtrLocation() == CodePtrLocation::kCallDirect; }
- int32_t GetStringInitOffset() const {
+ QuickEntrypointEnum GetStringInitEntryPoint() const {
DCHECK(IsStringInit());
- return dispatch_info_.method_load_data;
+ return static_cast<QuickEntrypointEnum>(dispatch_info_.method_load_data);
}
uint64_t GetMethodAddress() const {
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 11c18b0..931bbd3 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -49,6 +49,7 @@
shared_libs: [
"libart",
"libart-compiler",
+ "libbase",
"libsigchain",
],
}
@@ -62,6 +63,7 @@
shared_libs: [
"libartd",
"libartd-compiler",
+ "libbase",
"libsigchain",
],
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index c422163..3b2715d 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -450,7 +450,11 @@
// it's rather easy to hang in unwinding.
// LogLine also avoids ART logging lock issues, as it's really only a wrapper around
// logcat logging or stderr output.
- LogMessage::LogLine(__FILE__, __LINE__, LogSeverity::FATAL, message.c_str());
+ android::base::LogMessage::LogLine(__FILE__,
+ __LINE__,
+ android::base::LogId::DEFAULT,
+ LogSeverity::FATAL,
+ message.c_str());
exit(1);
}
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
index 64f2299..3e589f7 100644
--- a/dexdump/Android.bp
+++ b/dexdump/Android.bp
@@ -22,7 +22,10 @@
"dexdump.cc",
],
cflags: ["-Wall"],
- shared_libs: ["libart"],
+ shared_libs: [
+ "libart",
+ "libbase",
+ ],
}
art_cc_test {
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index c411572..296cdb6 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -22,7 +22,10 @@
"dex_ir_builder.cc",
],
cflags: ["-Wall"],
- shared_libs: ["libart"],
+ shared_libs: [
+ "libart",
+ "libbase",
+ ],
}
art_cc_test {
diff --git a/imgdiag/Android.bp b/imgdiag/Android.bp
index 7837d66..eaeb78e 100644
--- a/imgdiag/Android.bp
+++ b/imgdiag/Android.bp
@@ -26,7 +26,10 @@
// that the image it's analyzing be the same ISA as the runtime ISA.
compile_multilib: "both",
- shared_libs: ["libbacktrace"],
+ shared_libs: [
+ "libbacktrace",
+ "libbase",
+ ],
target: {
android: {
shared_libs: ["libcutils"],
diff --git a/oatdump/Android.bp b/oatdump/Android.bp
index dd6331c..bbe6cc1 100644
--- a/oatdump/Android.bp
+++ b/oatdump/Android.bp
@@ -34,6 +34,7 @@
"libart",
"libart-compiler",
"libart-disassembler",
+ "libbase",
],
}
@@ -47,6 +48,7 @@
"libartd",
"libartd-compiler",
"libartd-disassembler",
+ "libbase",
],
}
diff --git a/patchoat/Android.bp b/patchoat/Android.bp
index 8d8d6d1..a78f97d 100644
--- a/patchoat/Android.bp
+++ b/patchoat/Android.bp
@@ -24,6 +24,9 @@
compile_multilib: "prefer32",
},
},
+ shared_libs: [
+ "libbase",
+ ],
}
art_cc_binary {
diff --git a/profman/Android.bp b/profman/Android.bp
index 322dda2..2dcbaee 100644
--- a/profman/Android.bp
+++ b/profman/Android.bp
@@ -32,6 +32,10 @@
include_dirs: [
"art/cmdline",
],
+
+ shared_libs: [
+ "libbase",
+ ],
}
art_cc_binary {
diff --git a/runtime/Android.bp b/runtime/Android.bp
index ad953ea..fd9b5b9 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -470,6 +470,7 @@
srcs: ["common_runtime_test.cc"],
shared_libs: [
"libartd",
+ "libbase",
],
}
diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h
index d2f0fdb..f0811b0 100644
--- a/runtime/base/bit_utils.h
+++ b/runtime/base/bit_utils.h
@@ -21,13 +21,8 @@
#include <limits>
#include <type_traits>
-// This header is used in the disassembler with libbase's logging. Only include ART logging
-// when no other logging macros are available. b/15436106, b/31338270
-#ifndef CHECK
-#include "base/logging.h"
-#endif
-
#include "base/iteration_range.h"
+#include "base/logging.h"
#include "base/stl_util.h"
namespace art {
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index e00e62d..17873b5 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -28,6 +28,7 @@
// Headers for LogMessage::LogLine.
#ifdef ART_TARGET_ANDROID
#include "cutils/log.h"
+#include <android/set_abort_message.h>
#else
#include <sys/types.h>
#include <unistd.h>
@@ -39,24 +40,10 @@
unsigned int gAborting = 0;
-static LogSeverity gMinimumLogSeverity = INFO;
static std::unique_ptr<std::string> gCmdLine;
static std::unique_ptr<std::string> gProgramInvocationName;
static std::unique_ptr<std::string> gProgramInvocationShortName;
-// Print INTERNAL_FATAL messages directly instead of at destruction time. This only works on the
-// host right now: for the device, a stream buf collating output into lines and calling LogLine or
-// lower-level logging is necessary.
-#ifdef ART_TARGET_ANDROID
-static constexpr bool kPrintInternalFatalDirectly = false;
-#else
-static constexpr bool kPrintInternalFatalDirectly = !kIsTargetBuild;
-#endif
-
-static bool PrintDirectly(LogSeverity severity) {
- return kPrintInternalFatalDirectly && severity == INTERNAL_FATAL;
-}
-
const char* GetCmdLine() {
return (gCmdLine.get() != nullptr) ? gCmdLine->c_str() : nullptr;
}
@@ -70,6 +57,16 @@
: "art";
}
+NO_RETURN
+static void RuntimeAborter(const char* abort_message) {
+#ifdef __ANDROID__
+ android_set_abort_message(abort_message);
+#else
+ UNUSED(abort_message);
+#endif
+ Runtime::Abort();
+}
+
void InitLogging(char* argv[]) {
if (gCmdLine.get() != nullptr) {
return;
@@ -94,150 +91,14 @@
// TODO: fall back to /proc/self/cmdline when argv is null on Linux.
gCmdLine.reset(new std::string("<unset>"));
}
- const char* tags = getenv("ANDROID_LOG_TAGS");
- if (tags == nullptr) {
- return;
- }
- std::vector<std::string> specs;
- Split(tags, ' ', &specs);
- for (size_t i = 0; i < specs.size(); ++i) {
- // "tag-pattern:[vdiwefs]"
- std::string spec(specs[i]);
- if (spec.size() == 3 && StartsWith(spec, "*:")) {
- switch (spec[2]) {
- case 'v':
- gMinimumLogSeverity = VERBOSE;
- continue;
- case 'd':
- gMinimumLogSeverity = DEBUG;
- continue;
- case 'i':
- gMinimumLogSeverity = INFO;
- continue;
- case 'w':
- gMinimumLogSeverity = WARNING;
- continue;
- case 'e':
- gMinimumLogSeverity = ERROR;
- continue;
- case 'f':
- gMinimumLogSeverity = FATAL;
- continue;
- // liblog will even suppress FATAL if you say 's' for silent, but that's crazy!
- case 's':
- gMinimumLogSeverity = FATAL;
- continue;
- }
- }
- LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags << ")";
- }
-}
-
-// This indirection greatly reduces the stack impact of having
-// lots of checks/logging in a function.
-class LogMessageData {
- public:
- LogMessageData(const char* file, unsigned int line, LogSeverity severity, int error)
- : file_(GetFilenameBase(file)),
- line_number_(line),
- severity_(severity),
- error_(error) {}
-
- const char * GetFile() const {
- return file_;
- }
-
- unsigned int GetLineNumber() const {
- return line_number_;
- }
-
- LogSeverity GetSeverity() const {
- return severity_;
- }
-
- int GetError() const {
- return error_;
- }
-
- std::ostream& GetBuffer() {
- return buffer_;
- }
-
- std::string ToString() const {
- return buffer_.str();
- }
-
- private:
- std::ostringstream buffer_;
- const char* const file_;
- const unsigned int line_number_;
- const LogSeverity severity_;
- const int error_;
-
- static const char* GetFilenameBase(const char* file) {
- const char* last_slash = strrchr(file, '/');
- return (last_slash == nullptr) ? file : last_slash + 1;
- }
-
- DISALLOW_COPY_AND_ASSIGN(LogMessageData);
-};
-
-
-LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, int error)
- : data_(new LogMessageData(file, line, severity, error)) {
- if (PrintDirectly(severity)) {
- static constexpr char kLogCharacters[] = { 'V', 'D', 'I', 'W', 'E', 'F', 'F' };
- static_assert(arraysize(kLogCharacters) == static_cast<size_t>(INTERNAL_FATAL) + 1,
- "Wrong character array size");
- stream() << ProgramInvocationShortName() << " " << kLogCharacters[static_cast<size_t>(severity)]
- << " " << getpid() << " " << ::art::GetTid() << " " << file << ":" << line << "]";
- }
-}
-LogMessage::~LogMessage() {
- if (PrintDirectly(data_->GetSeverity())) {
- // Add newline at the end to match the not printing directly behavior.
- std::cerr << '\n';
- } else {
- if (data_->GetSeverity() < gMinimumLogSeverity) {
- return; // No need to format something we're not going to output.
- }
-
- // Finish constructing the message.
- if (data_->GetError() != -1) {
- data_->GetBuffer() << ": " << strerror(data_->GetError());
- }
- std::string msg(data_->ToString());
-
- // Do the actual logging with the lock held.
- {
- MutexLock mu(Thread::Current(), *Locks::logging_lock_);
- if (msg.find('\n') == std::string::npos) {
- LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), msg.c_str());
- } else {
- msg += '\n';
- size_t i = 0;
- while (i < msg.size()) {
- size_t nl = msg.find('\n', i);
- msg[nl] = '\0';
- LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), &msg[i]);
- i = nl + 1;
- }
- }
- }
- }
-
- // Abort if necessary.
- if (data_->GetSeverity() == FATAL) {
- Runtime::Abort();
- }
-}
-
-std::ostream& LogMessage::stream() {
- if (PrintDirectly(data_->GetSeverity())) {
- return std::cerr;
- }
- return data_->GetBuffer();
+#ifdef __ANDROID__
+#define INIT_LOGGING_DEFAULT_LOGGER android::base::LogdLogger()
+#else
+#define INIT_LOGGING_DEFAULT_LOGGER android::base::StderrLogger
+#endif
+ android::base::InitLogging(argv, INIT_LOGGING_DEFAULT_LOGGER, RuntimeAborter);
+#undef INIT_LOGGING_DEFAULT_LOGGER
}
#ifdef ART_TARGET_ANDROID
@@ -245,31 +106,14 @@
ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_FATAL
};
-static_assert(arraysize(kLogSeverityToAndroidLogPriority) == INTERNAL_FATAL + 1,
+static_assert(arraysize(kLogSeverityToAndroidLogPriority) == ::android::base::FATAL + 1,
"Mismatch in size of kLogSeverityToAndroidLogPriority and values in LogSeverity");
#endif
-void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity log_severity,
- const char* message) {
-#ifdef ART_TARGET_ANDROID
- const char* tag = ProgramInvocationShortName();
- int priority = kLogSeverityToAndroidLogPriority[static_cast<size_t>(log_severity)];
- if (priority == ANDROID_LOG_FATAL) {
- LOG_PRI(priority, tag, "%s:%u] %s", file, line, message);
- } else {
- LOG_PRI(priority, tag, "%s", message);
- }
-#else
- static const char* log_characters = "VDIWEFF";
- CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
- char severity = log_characters[log_severity];
- fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n",
- ProgramInvocationShortName(), severity, getpid(), ::art::GetTid(), file, line, message);
-#endif
-}
-
-void LogMessage::LogLineLowStack(const char* file, unsigned int line, LogSeverity log_severity,
- const char* message) {
+void LogHelper::LogLineLowStack(const char* file,
+ unsigned int line,
+ LogSeverity log_severity,
+ const char* message) {
#ifdef ART_TARGET_ANDROID
// Use android_writeLog() to avoid stack-based buffers used by android_printLog().
const char* tag = ProgramInvocationShortName();
@@ -292,8 +136,9 @@
}
#else
static constexpr char kLogCharacters[] = { 'V', 'D', 'I', 'W', 'E', 'F', 'F' };
- static_assert(arraysize(kLogCharacters) == static_cast<size_t>(INTERNAL_FATAL) + 1,
- "Wrong character array size");
+ static_assert(
+ arraysize(kLogCharacters) == static_cast<size_t>(::android::base::FATAL) + 1,
+ "Wrong character array size");
const char* program_name = ProgramInvocationShortName();
TEMP_FAILURE_RETRY(write(STDERR_FILENO, program_name, strlen(program_name)));
@@ -310,13 +155,4 @@
#endif // ART_TARGET_ANDROID
}
-ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
- old_ = gMinimumLogSeverity;
- gMinimumLogSeverity = level;
-}
-
-ScopedLogSeverity::~ScopedLogSeverity() {
- gMinimumLogSeverity = old_;
-}
-
} // namespace art
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index 185aa0e..5f84204 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -18,20 +18,16 @@
#define ART_RUNTIME_BASE_LOGGING_H_
#include <ostream>
+#include <sstream>
+#include "android-base/logging.h"
#include "base/macros.h"
namespace art {
-enum LogSeverity {
- VERBOSE,
- DEBUG,
- INFO,
- WARNING,
- ERROR,
- FATAL,
- INTERNAL_FATAL, // For Runtime::Abort.
-};
+// Make libbase's LogSeverity more easily available.
+using ::android::base::LogSeverity;
+using ::android::base::ScopedLogSeverity;
// The members of this struct are the valid arguments to VLOG and VLOG_IS_ON in code,
// and the "-verbose:" command line argument.
@@ -89,172 +85,28 @@
// hasn't been performed then just returns "art"
extern const char* ProgramInvocationShortName();
-// Logs a message to logcat on Android otherwise to stderr. If the severity is FATAL it also causes
-// an abort. For example: LOG(FATAL) << "We didn't expect to reach here";
-#define LOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, -1).stream()
+class LogHelper {
+ public:
+ // A logging helper for logging a single line. Can be used with little stack.
+ static void LogLineLowStack(const char* file,
+ unsigned int line,
+ android::base::LogSeverity severity,
+ const char* msg);
-// A variant of LOG that also logs the current errno value. To be used when library calls fail.
-#define PLOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, errno).stream()
-
-// Marker that code is yet to be implemented.
-#define UNIMPLEMENTED(level) LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
+ private:
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(LogHelper);
+};
// Is verbose logging enabled for the given module? Where the module is defined in LogVerbosity.
#define VLOG_IS_ON(module) UNLIKELY(::art::gLogVerbosity.module)
// Variant of LOG that logs when verbose logging is enabled for a module. For example,
// VLOG(jni) << "A JNI operation was performed";
-#define VLOG(module) \
- if (VLOG_IS_ON(module)) \
- ::art::LogMessage(__FILE__, __LINE__, INFO, -1).stream()
+#define VLOG(module) if (VLOG_IS_ON(module)) LOG(INFO)
// Return the stream associated with logging for the given module.
-#define VLOG_STREAM(module) ::art::LogMessage(__FILE__, __LINE__, INFO, -1).stream()
-
-// Check whether condition x holds and LOG(FATAL) if not. The value of the expression x is only
-// evaluated once. Extra logging can be appended using << after. For example,
-// CHECK(false == true) results in a log message of "Check failed: false == true".
-#define CHECK(x) \
- if (UNLIKELY(!(x))) \
- ::art::LogMessage(__FILE__, __LINE__, ::art::FATAL, -1).stream() \
- << "Check failed: " #x << " "
-
-// Helper for CHECK_xx(x,y) macros.
-#define CHECK_OP(LHS, RHS, OP) \
- for (auto _values = ::art::MakeEagerEvaluator(LHS, RHS); \
- UNLIKELY(!(_values.lhs OP _values.rhs)); /* empty */) \
- ::art::LogMessage(__FILE__, __LINE__, ::art::FATAL, -1).stream() \
- << "Check failed: " << #LHS << " " << #OP << " " << #RHS \
- << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
-
-
-// Check whether a condition holds between x and y, LOG(FATAL) if not. The value of the expressions
-// x and y is evaluated once. Extra logging can be appended using << after. For example,
-// CHECK_NE(0 == 1, false) results in "Check failed: false != false (0==1=false, false=false) ".
-#define CHECK_EQ(x, y) CHECK_OP(x, y, ==)
-#define CHECK_NE(x, y) CHECK_OP(x, y, !=)
-#define CHECK_LE(x, y) CHECK_OP(x, y, <=)
-#define CHECK_LT(x, y) CHECK_OP(x, y, <)
-#define CHECK_GE(x, y) CHECK_OP(x, y, >=)
-#define CHECK_GT(x, y) CHECK_OP(x, y, >)
-
-// Helper for CHECK_STRxx(s1,s2) macros.
-#define CHECK_STROP(s1, s2, sense) \
- if (UNLIKELY((strcmp(s1, s2) == 0) != (sense))) \
- LOG(::art::FATAL) << "Check failed: " \
- << "\"" << (s1) << "\"" \
- << ((sense) ? " == " : " != ") \
- << "\"" << (s2) << "\""
-
-// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not.
-#define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
-#define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false)
-
-// Perform the pthread function call(args), LOG(FATAL) on error.
-#define CHECK_PTHREAD_CALL(call, args, what) \
- do { \
- int rc = call args; \
- if (rc != 0) { \
- errno = rc; \
- PLOG(::art::FATAL) << # call << " failed for " << (what); \
- } \
- } while (false)
-
-
-// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally CHECK should be
-// used unless profiling identifies a CHECK as being in performance critical code.
-#if defined(NDEBUG)
-static constexpr bool kEnableDChecks = false;
-#else
-static constexpr bool kEnableDChecks = true;
-#endif
-
-#define DCHECK(x) if (::art::kEnableDChecks) CHECK(x)
-#define DCHECK_EQ(x, y) if (::art::kEnableDChecks) CHECK_EQ(x, y)
-#define DCHECK_NE(x, y) if (::art::kEnableDChecks) CHECK_NE(x, y)
-#define DCHECK_LE(x, y) if (::art::kEnableDChecks) CHECK_LE(x, y)
-#define DCHECK_LT(x, y) if (::art::kEnableDChecks) CHECK_LT(x, y)
-#define DCHECK_GE(x, y) if (::art::kEnableDChecks) CHECK_GE(x, y)
-#define DCHECK_GT(x, y) if (::art::kEnableDChecks) CHECK_GT(x, y)
-#define DCHECK_STREQ(s1, s2) if (::art::kEnableDChecks) CHECK_STREQ(s1, s2)
-#define DCHECK_STRNE(s1, s2) if (::art::kEnableDChecks) CHECK_STRNE(s1, s2)
-
-// Temporary class created to evaluate the LHS and RHS, used with MakeEagerEvaluator to infer the
-// types of LHS and RHS.
-template <typename LHS, typename RHS>
-struct EagerEvaluator {
- constexpr EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) { }
- LHS lhs;
- RHS rhs;
-};
-
-// Helper function for CHECK_xx.
-template <typename LHS, typename RHS>
-constexpr EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
- return EagerEvaluator<LHS, RHS>(lhs, rhs);
-}
-
-// Explicitly instantiate EagerEvalue for pointers so that char*s aren't treated as strings. To
-// compare strings use CHECK_STREQ and CHECK_STRNE. We rely on signed/unsigned warnings to
-// protect you against combinations not explicitly listed below.
-#define EAGER_PTR_EVALUATOR(T1, T2) \
- template <> struct EagerEvaluator<T1, T2> { \
- EagerEvaluator(T1 l, T2 r) \
- : lhs(reinterpret_cast<const void*>(l)), \
- rhs(reinterpret_cast<const void*>(r)) { } \
- const void* lhs; \
- const void* rhs; \
- }
-EAGER_PTR_EVALUATOR(const char*, const char*);
-EAGER_PTR_EVALUATOR(const char*, char*);
-EAGER_PTR_EVALUATOR(char*, const char*);
-EAGER_PTR_EVALUATOR(char*, char*);
-EAGER_PTR_EVALUATOR(const unsigned char*, const unsigned char*);
-EAGER_PTR_EVALUATOR(const unsigned char*, unsigned char*);
-EAGER_PTR_EVALUATOR(unsigned char*, const unsigned char*);
-EAGER_PTR_EVALUATOR(unsigned char*, unsigned char*);
-EAGER_PTR_EVALUATOR(const signed char*, const signed char*);
-EAGER_PTR_EVALUATOR(const signed char*, signed char*);
-EAGER_PTR_EVALUATOR(signed char*, const signed char*);
-EAGER_PTR_EVALUATOR(signed char*, signed char*);
-
-// Data for the log message, not stored in LogMessage to avoid increasing the stack size.
-class LogMessageData;
-
-// A LogMessage is a temporarily scoped object used by LOG and the unlikely part of a CHECK. The
-// destructor will abort if the severity is FATAL.
-class LogMessage {
- public:
- LogMessage(const char* file, unsigned int line, LogSeverity severity, int error);
-
- ~LogMessage(); // TODO: enable REQUIRES(!Locks::logging_lock_).
-
- // Returns the stream associated with the message, the LogMessage performs output when it goes
- // out of scope.
- std::ostream& stream();
-
- // The routine that performs the actual logging.
- static void LogLine(const char* file, unsigned int line, LogSeverity severity, const char* msg);
-
- // A variant of the above for use with little stack.
- static void LogLineLowStack(const char* file, unsigned int line, LogSeverity severity,
- const char* msg);
-
- private:
- const std::unique_ptr<LogMessageData> data_;
-
- DISALLOW_COPY_AND_ASSIGN(LogMessage);
-};
-
-// Allows to temporarily change the minimum severity level for logging.
-class ScopedLogSeverity {
- public:
- explicit ScopedLogSeverity(LogSeverity level);
- ~ScopedLogSeverity();
-
- private:
- LogSeverity old_;
-};
+#define VLOG_STREAM(module) LOG_STREAM(INFO)
} // namespace art
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 43c38c4..9d56954 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -328,14 +328,20 @@
bool shutting_down = IsShuttingDown();
#if ART_USE_FUTEXES
if (state_.LoadRelaxed() != 0) {
- LOG(shutting_down ? WARNING : FATAL) << "destroying mutex with owner: " << exclusive_owner_;
+ LOG(shutting_down
+ ? ::android::base::WARNING
+ : ::android::base::FATAL) << "destroying mutex with owner: " << exclusive_owner_;
} else {
if (exclusive_owner_ != 0) {
- LOG(shutting_down ? WARNING : FATAL) << "unexpectedly found an owner on unlocked mutex "
+ LOG(shutting_down
+ ? ::android::base::WARNING
+ : ::android::base::FATAL) << "unexpectedly found an owner on unlocked mutex "
<< name_;
}
if (num_contenders_.LoadSequentiallyConsistent() != 0) {
- LOG(shutting_down ? WARNING : FATAL) << "unexpectedly found a contender on mutex " << name_;
+ LOG(shutting_down
+ ? ::android::base::WARNING
+ : ::android::base::FATAL) << "unexpectedly found a contender on mutex " << name_;
}
}
#else
@@ -346,7 +352,9 @@
errno = rc;
// TODO: should we just not log at all if shutting down? this could be the logging mutex!
MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
- PLOG(shutting_down ? WARNING : FATAL) << "pthread_mutex_destroy failed for " << name_;
+ PLOG(shutting_down
+ ? ::android::base::WARNING
+ : ::android::base::FATAL) << "pthread_mutex_destroy failed for " << name_;
}
#endif
}
@@ -480,9 +488,11 @@
if (this != Locks::logging_lock_) {
LOG(FATAL) << "Unexpected state_ in unlock " << cur_state << " for " << name_;
} else {
- LogMessage::LogLine(__FILE__, __LINE__, INTERNAL_FATAL,
- StringPrintf("Unexpected state_ %d in unlock for %s",
- cur_state, name_).c_str());
+ LogHelper::LogLineLowStack(__FILE__,
+ __LINE__,
+ ::android::base::FATAL_WITHOUT_ABORT,
+ StringPrintf("Unexpected state_ %d in unlock for %s",
+ cur_state, name_).c_str());
_exit(1);
}
}
@@ -762,7 +772,10 @@
if (num_waiters_!= 0) {
Runtime* runtime = Runtime::Current();
bool shutting_down = runtime == nullptr || runtime->IsShuttingDown(Thread::Current());
- LOG(shutting_down ? WARNING : FATAL) << "ConditionVariable::~ConditionVariable for " << name_
+ LOG(shutting_down
+ ? ::android::base::WARNING
+ : ::android::base::FATAL)
+ << "ConditionVariable::~ConditionVariable for " << name_
<< " called with " << num_waiters_ << " waiters.";
}
#else
@@ -774,7 +787,9 @@
MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
Runtime* runtime = Runtime::Current();
bool shutting_down = (runtime == nullptr) || runtime->IsShuttingDownLocked();
- PLOG(shutting_down ? WARNING : FATAL) << "pthread_cond_destroy failed for " << name_;
+ PLOG(shutting_down
+ ? ::android::base::WARNING
+ : ::android::base::FATAL) << "pthread_cond_destroy failed for " << name_;
}
#endif
}
diff --git a/runtime/base/stl_util.h b/runtime/base/stl_util.h
index a4cf249..a53dcea 100644
--- a/runtime/base/stl_util.h
+++ b/runtime/base/stl_util.h
@@ -20,11 +20,7 @@
#include <algorithm>
#include <sstream>
-// This header is used in the disassembler with libbase's logging. Only include ART logging
-// when no other logging macros are available. b/15436106, b/31338270
-#ifndef CHECK
#include "base/logging.h"
-#endif
namespace art {
diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc
index 48e3ceb..4498198 100644
--- a/runtime/base/unix_file/fd_file.cc
+++ b/runtime/base/unix_file/fd_file.cc
@@ -64,16 +64,16 @@
void FdFile::Destroy() {
if (kCheckSafeUsage && (guard_state_ < GuardState::kNoCheck)) {
if (guard_state_ < GuardState::kFlushed) {
- LOG(::art::ERROR) << "File " << file_path_ << " wasn't explicitly flushed before destruction.";
+ LOG(ERROR) << "File " << file_path_ << " wasn't explicitly flushed before destruction.";
}
if (guard_state_ < GuardState::kClosed) {
- LOG(::art::ERROR) << "File " << file_path_ << " wasn't explicitly closed before destruction.";
+ LOG(ERROR) << "File " << file_path_ << " wasn't explicitly closed before destruction.";
}
CHECK_GE(guard_state_, GuardState::kClosed);
}
if (auto_close_ && fd_ != -1) {
if (Close() != 0) {
- PLOG(::art::WARNING) << "Failed to close file " << file_path_;
+ PLOG(WARNING) << "Failed to close file " << file_path_;
}
}
}
@@ -104,7 +104,7 @@
if (kCheckSafeUsage) {
if (guard_state_ < GuardState::kNoCheck) {
if (warn_threshold < GuardState::kNoCheck && guard_state_ >= warn_threshold) {
- LOG(::art::ERROR) << warning;
+ LOG(ERROR) << warning;
}
guard_state_ = target;
}
@@ -117,7 +117,7 @@
if (guard_state_ < target) {
guard_state_ = target;
} else if (target < guard_state_) {
- LOG(::art::ERROR) << warning;
+ LOG(ERROR) << warning;
}
}
}
@@ -350,13 +350,13 @@
DCHECK(!read_only_mode_);
int flush_result = TEMP_FAILURE_RETRY(Flush());
if (flush_result != 0) {
- LOG(::art::ERROR) << "CloseOrErase failed while flushing a file.";
+ LOG(ERROR) << "CloseOrErase failed while flushing a file.";
Erase();
return flush_result;
}
int close_result = TEMP_FAILURE_RETRY(Close());
if (close_result != 0) {
- LOG(::art::ERROR) << "CloseOrErase failed while closing a file.";
+ LOG(ERROR) << "CloseOrErase failed while closing a file.";
Erase();
return close_result;
}
@@ -367,11 +367,11 @@
DCHECK(!read_only_mode_);
int flush_result = TEMP_FAILURE_RETRY(Flush());
if (flush_result != 0) {
- LOG(::art::ERROR) << "FlushClose failed while flushing a file.";
+ LOG(ERROR) << "FlushClose failed while flushing a file.";
}
int close_result = TEMP_FAILURE_RETRY(Close());
if (close_result != 0) {
- LOG(::art::ERROR) << "FlushClose failed while closing a file.";
+ LOG(ERROR) << "FlushClose failed while closing a file.";
}
return (flush_result != 0) ? flush_result : close_result;
}
@@ -383,7 +383,7 @@
bool FdFile::ClearContent() {
DCHECK(!read_only_mode_);
if (SetLength(0) < 0) {
- PLOG(art::ERROR) << "Failed to reset the length";
+ PLOG(ERROR) << "Failed to reset the length";
return false;
}
return ResetOffset();
@@ -393,7 +393,7 @@
DCHECK(!read_only_mode_);
off_t rc = TEMP_FAILURE_RETRY(lseek(fd_, 0, SEEK_SET));
if (rc == static_cast<off_t>(-1)) {
- PLOG(art::ERROR) << "Failed to reset the offset";
+ PLOG(ERROR) << "Failed to reset the offset";
return false;
}
return true;
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index 6683f13..a980535 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -275,7 +275,7 @@
return false;
}
if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o)) {
- Runtime::Current()->GetHeap()->DumpSpaces(LOG(ERROR));
+ Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
AbortF("field operation on invalid %s: %p",
ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
java_object);
@@ -783,7 +783,7 @@
}
if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(obj)) {
- Runtime::Current()->GetHeap()->DumpSpaces(LOG(ERROR));
+ Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
AbortF("%s is an invalid %s: %p (%p)",
what, ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
java_object, obj);
@@ -1109,7 +1109,7 @@
mirror::Array* a = soa.Decode<mirror::Array*>(java_array);
if (UNLIKELY(!Runtime::Current()->GetHeap()->IsValidObjectAddress(a))) {
- Runtime::Current()->GetHeap()->DumpSpaces(LOG(ERROR));
+ Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
AbortF("jarray is an invalid %s: %p (%p)",
ToStr<IndirectRefKind>(GetIndirectRefKind(java_array)).c_str(),
java_array, a);
@@ -1146,7 +1146,7 @@
ArtField* f = soa.DecodeField(fid);
// TODO: Better check here.
if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(f->GetDeclaringClass())) {
- Runtime::Current()->GetHeap()->DumpSpaces(LOG(ERROR));
+ Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
AbortF("invalid jfieldID: %p", fid);
return nullptr;
}
@@ -1162,7 +1162,7 @@
ArtMethod* m = soa.DecodeMethod(mid);
// TODO: Better check here.
if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(m->GetDeclaringClass())) {
- Runtime::Current()->GetHeap()->DumpSpaces(LOG(ERROR));
+ Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
AbortF("invalid jmethodID: %p", mid);
return nullptr;
}
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 2dbb1fd..ecaa4c2 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7921,7 +7921,7 @@
explicit DumpClassVisitor(int flags) : flags_(flags) {}
bool operator()(mirror::Class* klass) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
- klass->DumpClass(LOG(ERROR), flags_);
+ klass->DumpClass(LOG_STREAM(ERROR), flags_);
return true;
}
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 8a48604..11722b2 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -58,7 +58,7 @@
setenv("ANDROID_LOG_TAGS", "*:e", 1);
art::InitLogging(argv);
- LOG(::art::INFO) << "Running main() from common_runtime_test.cc...";
+ LOG(INFO) << "Running main() from common_runtime_test.cc...";
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
index 5b9d03b..343343f 100644
--- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
@@ -36,7 +36,7 @@
// specialized visitor that will show whether a method is Quick or Shadow.
} else {
LOG(INFO) << "Deopting:";
- self->Dump(LOG(INFO));
+ self->Dump(LOG_STREAM(INFO));
}
}
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index f86921c..f9345b6 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -438,7 +438,7 @@
// above.
abort();
#endif
- self->DumpJavaStack(LOG(ERROR));
+ self->DumpJavaStack(LOG_STREAM(ERROR));
}
return false; // Return false since we want to propagate the fault to the main signal handler.
diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc
index 24a2c17..3b6750e 100644
--- a/runtime/gc/accounting/mod_union_table.cc
+++ b/runtime/gc/accounting/mod_union_table.cc
@@ -283,7 +283,7 @@
<< from_space->GetGcRetentionPolicy();
LOG(INFO) << "ToSpace " << to_space->GetName() << " type "
<< to_space->GetGcRetentionPolicy();
- heap->DumpSpaces(LOG(INFO));
+ heap->DumpSpaces(LOG_STREAM(INFO));
LOG(FATAL) << "FATAL ERROR";
}
}
diff --git a/runtime/gc/allocator/dlmalloc.cc b/runtime/gc/allocator/dlmalloc.cc
index dc4e312..0c84224 100644
--- a/runtime/gc/allocator/dlmalloc.cc
+++ b/runtime/gc/allocator/dlmalloc.cc
@@ -37,6 +37,9 @@
#pragma GCC diagnostic ignored "-Wempty-body"
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
#include "../../../external/dlmalloc/malloc.c"
+// Note: malloc.c uses a DEBUG define to drive debug code. This interferes with the DEBUG severity
+// of libbase, so undefine it now.
+#undef DEBUG
#pragma GCC diagnostic pop
static void* art_heap_morecore(void* m, intptr_t increment) {
@@ -44,11 +47,11 @@
}
static void art_heap_corruption(const char* function) {
- LOG(::art::FATAL) << "Corrupt heap detected in: " << function;
+ LOG(FATAL) << "Corrupt heap detected in: " << function;
}
static void art_heap_usage_error(const char* function, void* p) {
- LOG(::art::FATAL) << "Incorrect use of function '" << function << "' argument " << p
+ LOG(FATAL) << "Incorrect use of function '" << function << "' argument " << p
<< " not expected";
}
@@ -69,7 +72,7 @@
int rc = madvise(start, length, MADV_DONTNEED);
if (UNLIKELY(rc != 0)) {
errno = rc;
- PLOG(::art::FATAL) << "madvise failed during heap trimming";
+ PLOG(FATAL) << "madvise failed during heap trimming";
}
size_t* reclaimed = reinterpret_cast<size_t*>(arg);
*reclaimed += length;
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 2750fea..ab8942a 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -430,7 +430,7 @@
TimingLogger::ScopedTiming split("FlipThreadRoots", GetTimings());
if (kVerboseMode) {
LOG(INFO) << "time=" << region_space_->Time();
- region_space_->DumpNonFreeRegions(LOG(INFO));
+ region_space_->DumpNonFreeRegions(LOG_STREAM(INFO));
}
Thread* self = Thread::Current();
Locks::mutator_lock_->AssertNotHeld(self);
@@ -447,7 +447,7 @@
QuasiAtomic::ThreadFenceForConstructor();
if (kVerboseMode) {
LOG(INFO) << "time=" << region_space_->Time();
- region_space_->DumpNonFreeRegions(LOG(INFO));
+ region_space_->DumpNonFreeRegions(LOG_STREAM(INFO));
LOG(INFO) << "GC end of FlipThreadRoots";
}
}
@@ -1622,7 +1622,7 @@
if (obj != nullptr) {
LogFromSpaceRefHolder(obj, offset);
}
- ref->GetLockWord(false).Dump(LOG(INTERNAL_FATAL));
+ ref->GetLockWord(false).Dump(LOG_STREAM(FATAL_WITHOUT_ABORT));
CHECK(false) << "Found from-space ref " << ref << " " << PrettyTypeOf(ref);
} else {
AssertToSpaceInvariantInNonMovingSpace(obj, ref);
@@ -1645,13 +1645,13 @@
template <class MirrorType>
void VisitRoot(mirror::Object** root)
REQUIRES_SHARED(Locks::mutator_lock_) {
- LOG(INTERNAL_FATAL) << "root=" << root << " ref=" << *root;
+ LOG(FATAL_WITHOUT_ABORT) << "root=" << root << " ref=" << *root;
}
template <class MirrorType>
void VisitRoot(mirror::CompressedReference<MirrorType>* root)
REQUIRES_SHARED(Locks::mutator_lock_) {
- LOG(INTERNAL_FATAL) << "root=" << root << " ref=" << root->AsMirrorPtr();
+ LOG(FATAL_WITHOUT_ABORT) << "root=" << root << " ref=" << root->AsMirrorPtr();
}
};
@@ -1670,19 +1670,19 @@
// No info.
} else if (gc_root_source->HasArtField()) {
ArtField* field = gc_root_source->GetArtField();
- LOG(INTERNAL_FATAL) << "gc root in field " << field << " " << PrettyField(field);
+ LOG(FATAL_WITHOUT_ABORT) << "gc root in field " << field << " " << PrettyField(field);
RootPrinter root_printer;
field->VisitRoots(root_printer);
} else if (gc_root_source->HasArtMethod()) {
ArtMethod* method = gc_root_source->GetArtMethod();
- LOG(INTERNAL_FATAL) << "gc root in method " << method << " " << PrettyMethod(method);
+ LOG(FATAL_WITHOUT_ABORT) << "gc root in method " << method << " " << PrettyMethod(method);
RootPrinter root_printer;
method->VisitRoots(root_printer, kRuntimePointerSize);
}
- ref->GetLockWord(false).Dump(LOG(INTERNAL_FATAL));
- region_space_->DumpNonFreeRegions(LOG(INTERNAL_FATAL));
- PrintFileToLog("/proc/self/maps", LogSeverity::INTERNAL_FATAL);
- MemMap::DumpMaps(LOG(INTERNAL_FATAL), true);
+ ref->GetLockWord(false).Dump(LOG_STREAM(FATAL_WITHOUT_ABORT));
+ region_space_->DumpNonFreeRegions(LOG_STREAM(FATAL_WITHOUT_ABORT));
+ PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT);
+ MemMap::DumpMaps(LOG_STREAM(FATAL_WITHOUT_ABORT), true);
CHECK(false) << "Found from-space ref " << ref << " " << PrettyTypeOf(ref);
} else {
AssertToSpaceInvariantInNonMovingSpace(nullptr, ref);
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index d866106..6d2f009 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -139,7 +139,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
// Marking a large object, make sure its aligned as a sanity check.
if (!IsAligned<kPageSize>(ref)) {
- Runtime::Current()->GetHeap()->DumpSpaces(LOG(ERROR));
+ Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
LOG(FATAL) << ref;
}
};
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index cbc4dc1..ad3dd33 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -413,11 +413,11 @@
if (UNLIKELY(obj == nullptr || !IsAligned<kPageSize>(obj) ||
(kIsDebugBuild && large_object_space != nullptr &&
!large_object_space->Contains(obj)))) {
- LOG(INTERNAL_FATAL) << "Tried to mark " << obj << " not contained by any spaces";
+ LOG(FATAL_WITHOUT_ABORT) << "Tried to mark " << obj << " not contained by any spaces";
if (holder_ != nullptr) {
size_t holder_size = holder_->SizeOf();
ArtField* field = holder_->FindFieldByOffset(offset_);
- LOG(INTERNAL_FATAL) << "Field info: "
+ LOG(FATAL_WITHOUT_ABORT) << "Field info: "
<< " holder=" << holder_
<< " holder is "
<< (mark_sweep_->GetHeap()->IsLiveObjectLocked(holder_)
@@ -440,13 +440,13 @@
// Print the memory content of the holder.
for (size_t i = 0; i < holder_size / sizeof(uint32_t); ++i) {
uint32_t* p = reinterpret_cast<uint32_t*>(holder_);
- LOG(INTERNAL_FATAL) << &p[i] << ": " << "holder+" << (i * sizeof(uint32_t)) << " = "
+ LOG(FATAL_WITHOUT_ABORT) << &p[i] << ": " << "holder+" << (i * sizeof(uint32_t)) << " = "
<< std::hex << p[i];
}
}
- PrintFileToLog("/proc/self/maps", LogSeverity::INTERNAL_FATAL);
- MemMap::DumpMaps(LOG(INTERNAL_FATAL), true);
- LOG(INTERNAL_FATAL) << "Attempting see if it's a bad thread root";
+ PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT);
+ MemMap::DumpMaps(LOG_STREAM(FATAL_WITHOUT_ABORT), true);
+ LOG(FATAL_WITHOUT_ABORT) << "Attempting see if it's a bad thread root";
mark_sweep_->VerifySuspendedThreadRoots();
LOG(FATAL) << "Can't mark invalid object";
}
@@ -574,7 +574,7 @@
if (heap->GetLiveBitmap()->GetContinuousSpaceBitmap(root) == nullptr) {
space::LargeObjectSpace* large_object_space = heap->GetLargeObjectsSpace();
if (large_object_space != nullptr && !large_object_space->Contains(root)) {
- LOG(INTERNAL_FATAL) << "Found invalid root: " << root << " " << info;
+ LOG(FATAL_WITHOUT_ABORT) << "Found invalid root: " << root << " " << info;
}
}
}
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index 47e6ca3..2e97172 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -296,7 +296,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) ALWAYS_INLINE {
mirror::Object* ref = obj->GetFieldObject<mirror::Object>(offset);
if (from_space_->HasAddress(ref)) {
- Runtime::Current()->GetHeap()->DumpObject(LOG(INFO), obj);
+ Runtime::Current()->GetHeap()->DumpObject(LOG_STREAM(INFO), obj);
LOG(FATAL) << ref << " found in from space";
}
}
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 11d4af8..4e6dd2b 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -630,7 +630,7 @@
bool no_gap = MemMap::CheckNoGaps(first_space->GetMemMap(), non_moving_space_->GetMemMap());
if (!no_gap) {
PrintFileToLog("/proc/self/maps", LogSeverity::ERROR);
- MemMap::DumpMaps(LOG(ERROR), true);
+ MemMap::DumpMaps(LOG_STREAM(ERROR), true);
LOG(FATAL) << "There's a gap between the image space and the non-moving space";
}
}
@@ -3157,14 +3157,14 @@
// Dump mod-union tables.
for (const auto& table_pair : mod_union_tables_) {
accounting::ModUnionTable* mod_union_table = table_pair.second;
- mod_union_table->Dump(LOG(ERROR) << mod_union_table->GetName() << ": ");
+ mod_union_table->Dump(LOG_STREAM(ERROR) << mod_union_table->GetName() << ": ");
}
// Dump remembered sets.
for (const auto& table_pair : remembered_sets_) {
accounting::RememberedSet* remembered_set = table_pair.second;
- remembered_set->Dump(LOG(ERROR) << remembered_set->GetName() << ": ");
+ remembered_set->Dump(LOG_STREAM(ERROR) << remembered_set->GetName() << ": ");
}
- DumpSpaces(LOG(ERROR));
+ DumpSpaces(LOG_STREAM(ERROR));
}
return visitor.GetFailureCount();
}
diff --git a/runtime/gc/reference_queue_test.cc b/runtime/gc/reference_queue_test.cc
index 35bf718..2a1635d 100644
--- a/runtime/gc/reference_queue_test.cc
+++ b/runtime/gc/reference_queue_test.cc
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <sstream>
+
#include "common_runtime_test.h"
#include "reference_queue.h"
#include "handle_scope-inl.h"
@@ -65,7 +67,9 @@
StackHandleScope<20> hs(self);
Mutex lock("Reference queue lock");
ReferenceQueue queue(&lock);
- queue.Dump(LOG(INFO));
+ std::ostringstream oss;
+ queue.Dump(oss);
+ LOG(INFO) << oss.str();
auto weak_ref_class = hs.NewHandle(
Runtime::Current()->GetClassLinker()->FindClass(self, "Ljava/lang/ref/WeakReference;",
ScopedNullHandle<mirror::ClassLoader>()));
@@ -78,10 +82,16 @@
ASSERT_TRUE(ref1.Get() != nullptr);
auto ref2(hs.NewHandle(finalizer_ref_class->AllocObject(self)->AsReference()));
ASSERT_TRUE(ref2.Get() != nullptr);
+
queue.EnqueueReference(ref1.Get());
- queue.Dump(LOG(INFO));
+ oss.str("");
+ queue.Dump(oss);
+ LOG(INFO) << oss.str();
+
queue.EnqueueReference(ref2.Get());
- queue.Dump(LOG(INFO));
+ oss.str("");
+ queue.Dump(oss);
+ LOG(INFO) << oss.str();
}
} // namespace gc
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 9c91732..a40e408 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -728,7 +728,7 @@
VLOG(image) << "ImageSpace::Init exiting " << *space.get();
if (VLOG_IS_ON(image)) {
- logger.Dump(LOG(INFO));
+ logger.Dump(LOG_STREAM(INFO));
}
return space;
}
@@ -1298,7 +1298,7 @@
}
}
if (VLOG_IS_ON(image)) {
- logger.Dump(LOG(INFO));
+ logger.Dump(LOG_STREAM(INFO));
}
return true;
}
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index 010f677..16d1f93 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -192,7 +192,7 @@
auto it = large_objects_.find(ptr);
if (UNLIKELY(it == large_objects_.end())) {
ScopedObjectAccess soa(self);
- Runtime::Current()->GetHeap()->DumpSpaces(LOG(INTERNAL_FATAL));
+ Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(FATAL_WITHOUT_ABORT));
LOG(FATAL) << "Attempted to free large object " << ptr << " which was not live";
}
MemMap* mem_map = it->second.mem_map;
diff --git a/runtime/gc/space/large_object_space_test.cc b/runtime/gc/space/large_object_space_test.cc
index ad38724..2544914 100644
--- a/runtime/gc/space/large_object_space_test.cc
+++ b/runtime/gc/space/large_object_space_test.cc
@@ -98,7 +98,9 @@
}
}
// Test that dump doesn't crash.
- los->Dump(LOG(INFO));
+ std::ostringstream oss;
+ los->Dump(oss);
+ LOG(INFO) << oss.str();
size_t bytes_allocated = 0, bytes_tl_bulk_allocated;
// Checks that the coalescing works.
diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc
index e24741a..23cae7c 100644
--- a/runtime/gc/space/region_space.cc
+++ b/runtime/gc/space/region_space.cc
@@ -38,7 +38,7 @@
if (mem_map.get() == nullptr) {
LOG(ERROR) << "Failed to allocate pages for alloc space (" << name << ") of size "
<< PrettySize(capacity) << " with message " << error_msg;
- MemMap::DumpMaps(LOG(ERROR));
+ MemMap::DumpMaps(LOG_STREAM(ERROR));
return nullptr;
}
return new RegionSpace(name, mem_map.release());
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 4f81b59..1f39a1e 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -188,7 +188,7 @@
ScopedObjectAccess soa(self);
LOG(WARNING) << "Attempt to remove non-JNI local reference, dumping thread";
if (kDumpStackOnNonLocalReference) {
- self->Dump(LOG(WARNING));
+ self->Dump(LOG_STREAM(WARNING));
}
}
return true;
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 77c3f0f..5934f13 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -576,9 +576,7 @@
// Replace calls to String.<init> with equivalent StringFactory call.
if (UNLIKELY(called_method->GetDeclaringClass()->IsStringClass()
&& called_method->IsConstructor())) {
- ScopedObjectAccessUnchecked soa(self);
- jmethodID mid = soa.EncodeMethod(called_method);
- called_method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ called_method = WellKnownClasses::StringInitToStringFactory(called_method);
string_init = true;
}
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index a8c7d15..cf8d4bd 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -38,8 +38,8 @@
int interp_size = (uintptr_t) artMterpAsmInstructionEnd -
(uintptr_t) artMterpAsmInstructionStart;
if ((interp_size == 0) || (interp_size != (art::kNumPackedOpcodes * width))) {
- LOG(art::FATAL) << "ERROR: unexpected asm interp size " << interp_size
- << "(did an instruction handler exceed " << width << " bytes?)";
+ LOG(FATAL) << "ERROR: unexpected asm interp size " << interp_size
+ << "(did an instruction handler exceed " << width << " bytes?)";
}
}
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index d505aea..98e358b 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -858,7 +858,7 @@
ArtMethod* init_method = h_real_to_string_class->FindDirectMethod(
"<init>", "()V", cl->GetImagePointerSize());
if (init_method == nullptr) {
- h_real_to_string_class->DumpClass(LOG(FATAL), mirror::Class::kDumpClassFullDetail);
+ h_real_to_string_class->DumpClass(LOG_STREAM(FATAL), mirror::Class::kDumpClassFullDetail);
} else {
JValue invoke_result;
EnterInterpreterFromInvoke(self, init_method, h_real_to_string_obj.Get(), nullptr,
diff --git a/runtime/jdwp/jdwp_socket.cc b/runtime/jdwp/jdwp_socket.cc
index 2507fe9..3be7fd6 100644
--- a/runtime/jdwp/jdwp_socket.cc
+++ b/runtime/jdwp/jdwp_socket.cc
@@ -121,7 +121,7 @@
netState->listenSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (netState->listenSock < 0) {
- PLOG(probe ? ERROR : FATAL) << "Socket create failed";
+ PLOG(probe ? ::android::base::ERROR : ::android::base::FATAL) << "Socket create failed";
goto fail;
}
@@ -129,7 +129,8 @@
{
int one = 1;
if (setsockopt(netState->listenSock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0) {
- PLOG(probe ? ERROR : FATAL) << "setsockopt(SO_REUSEADDR) failed";
+ PLOG(probe ? ::android::base::ERROR : ::android::base::FATAL)
+ << "setsockopt(SO_REUSEADDR) failed";
goto fail;
}
}
@@ -143,14 +144,15 @@
inet_aton("127.0.0.1", &addr.addrInet.sin_addr);
if (bind(netState->listenSock, &addr.addrPlain, sizeof(addr)) != 0) {
- PLOG(probe ? ERROR : FATAL) << "Attempt to bind to port " << port << " failed";
+ PLOG(probe ? ::android::base::ERROR : ::android::base::FATAL)
+ << "Attempt to bind to port " << port << " failed";
goto fail;
}
netState->listenPort = port;
if (listen(netState->listenSock, 5) != 0) {
- PLOG(probe ? ERROR : FATAL) << "Listen failed";
+ PLOG(probe ? ::android::base::ERROR : ::android::base::FATAL) << "Listen failed";
goto fail;
}
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index d984f45..afa52ca 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -337,7 +337,7 @@
Jit::~Jit() {
DCHECK(!profile_saver_options_.IsEnabled() || !ProfileSaver::IsStarted());
if (dump_info_on_shutdown_) {
- DumpInfo(LOG(INFO));
+ DumpInfo(LOG_STREAM(INFO));
}
DeleteThreadPool();
if (jit_compiler_handle_ != nullptr) {
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index 42916c3..a4bc3fc 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -447,7 +447,7 @@
}
instance_->shutting_down_ = true;
if (dump_info) {
- instance_->DumpInfo(LOG(INFO));
+ instance_->DumpInfo(LOG_STREAM(INFO));
}
}
diff --git a/runtime/jni_env_ext-inl.h b/runtime/jni_env_ext-inl.h
index dc6a3e8..685b056 100644
--- a/runtime/jni_env_ext-inl.h
+++ b/runtime/jni_env_ext-inl.h
@@ -32,9 +32,10 @@
if (check_jni) {
size_t entry_count = locals.Capacity();
if (entry_count > 16) {
- locals.Dump(LOG(WARNING) << "Warning: more than 16 JNI local references: "
- << entry_count << " (most recent was a " << PrettyTypeOf(obj) << ")\n");
- // TODO: LOG(FATAL) in a later release?
+ locals.Dump(LOG_STREAM(WARNING) << "Warning: more than 16 JNI local references: "
+ << entry_count << " (most recent was a "
+ << PrettyTypeOf(obj) << ")\n");
+ // TODO: LOG(FATAL) in a later release?
}
}
}
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index d9cb1c6..a11f9ab 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -100,8 +100,9 @@
static void ReportInvalidJNINativeMethod(const ScopedObjectAccess& soa, mirror::Class* c,
const char* kind, jint idx, bool return_errors)
REQUIRES_SHARED(Locks::mutator_lock_) {
- LOG(return_errors ? ERROR : FATAL) << "Failed to register native method in "
- << PrettyDescriptor(c) << " in " << c->GetDexCache()->GetLocation()->ToModifiedUtf8()
+ LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL)
+ << "Failed to register native method in " << PrettyDescriptor(c)
+ << " in " << c->GetDexCache()->GetLocation()->ToModifiedUtf8()
<< ": " << kind << " is null at index " << idx;
soa.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;",
"%s is null at index %d", kind, idx);
@@ -618,7 +619,8 @@
}
if (c->IsStringClass()) {
// Replace calls to String.<init> with equivalent StringFactory call.
- jmethodID sf_mid = WellKnownClasses::StringInitToStringFactoryMethodID(mid);
+ jmethodID sf_mid = soa.EncodeMethod(
+ WellKnownClasses::StringInitToStringFactory(soa.DecodeMethod(mid)));
return CallStaticObjectMethodV(env, WellKnownClasses::java_lang_StringFactory, sf_mid, args);
}
mirror::Object* result = c->AllocObject(soa.Self());
@@ -643,7 +645,8 @@
}
if (c->IsStringClass()) {
// Replace calls to String.<init> with equivalent StringFactory call.
- jmethodID sf_mid = WellKnownClasses::StringInitToStringFactoryMethodID(mid);
+ jmethodID sf_mid = soa.EncodeMethod(
+ WellKnownClasses::StringInitToStringFactory(soa.DecodeMethod(mid)));
return CallStaticObjectMethodA(env, WellKnownClasses::java_lang_StringFactory, sf_mid, args);
}
mirror::Object* result = c->AllocObject(soa.Self());
@@ -2226,16 +2229,20 @@
}
if (m == nullptr) {
- LOG(return_errors ? ERROR : INTERNAL_FATAL) << "Failed to register native method "
+ c->DumpClass(
+ LOG_STREAM(return_errors
+ ? ::android::base::ERROR
+ : ::android::base::FATAL_WITHOUT_ABORT),
+ mirror::Class::kDumpClassFullDetail);
+ LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL)
+ << "Failed to register native method "
<< PrettyDescriptor(c) << "." << name << sig << " in "
<< c->GetDexCache()->GetLocation()->ToModifiedUtf8();
- // Safe to pass in LOG(FATAL) since the log object aborts in destructor and only goes
- // out of scope after the DumpClass is done executing.
- c->DumpClass(LOG(return_errors ? ERROR : FATAL), mirror::Class::kDumpClassFullDetail);
ThrowNoSuchMethodError(soa, c, name, sig, "static or non-static");
return JNI_ERR;
} else if (!m->IsNative()) {
- LOG(return_errors ? ERROR : FATAL) << "Failed to register non-native method "
+ LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL)
+ << "Failed to register non-native method "
<< PrettyDescriptor(c) << "." << name << sig
<< " as native";
ThrowNoSuchMethodError(soa, c, name, sig, "native");
@@ -2478,7 +2485,7 @@
} else if (kWarnJniAbort && memcmp(array_data, elements, bytes) != 0) {
// Warn if we have JNI_ABORT and the arrays don't match since this is usually an error.
LOG(WARNING) << "Possible incorrect JNI_ABORT in Release*ArrayElements";
- soa.Self()->DumpJavaStack(LOG(WARNING));
+ soa.Self()->DumpJavaStack(LOG_STREAM(WARNING));
}
}
if (mode != JNI_COMMIT) {
@@ -3042,7 +3049,7 @@
os << "JNIWeakGlobalRefType";
return os;
default:
- LOG(::art::FATAL) << "jobjectRefType[" << static_cast<int>(rhs) << "]";
+ LOG(FATAL) << "jobjectRefType[" << static_cast<int>(rhs) << "]";
UNREACHABLE();
}
}
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index f21baed..2e5f532 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -147,8 +147,8 @@
void Class::SetClassSize(uint32_t new_class_size) {
if (kIsDebugBuild && new_class_size < GetClassSize()) {
- DumpClass(LOG(INTERNAL_FATAL), kDumpClassFullDetail);
- LOG(INTERNAL_FATAL) << new_class_size << " vs " << GetClassSize();
+ DumpClass(LOG_STREAM(FATAL_WITHOUT_ABORT), kDumpClassFullDetail);
+ LOG(FATAL_WITHOUT_ABORT) << new_class_size << " vs " << GetClassSize();
LOG(FATAL) << "class=" << PrettyTypeOf(this);
}
// Not called within a transaction.
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 22cc197..49b83a7 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -457,7 +457,7 @@
if (!Runtime::Current()->IsStarted() || VLOG_IS_ON(monitor)) {
std::ostringstream ss;
self->Dump(ss);
- LOG(Runtime::Current()->IsStarted() ? INFO : ERROR)
+ LOG(Runtime::Current()->IsStarted() ? ::android::base::INFO : ::android::base::ERROR)
<< self->GetException()->Dump() << "\n" << ss.str();
}
va_end(args);
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index 8f108fa..f09c067 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -240,8 +240,8 @@
ScopedObjectAccess soa(env);
LOG(INFO) << "--- reference table dump ---";
- soa.Env()->DumpReferenceTables(LOG(INFO));
- soa.Vm()->DumpReferenceTables(LOG(INFO));
+ soa.Env()->DumpReferenceTables(LOG_STREAM(INFO));
+ soa.Vm()->DumpReferenceTables(LOG_STREAM(INFO));
LOG(INFO) << "---";
}
diff --git a/runtime/openjdkjvm/Android.bp b/runtime/openjdkjvm/Android.bp
index 5ed1615..37112b6 100644
--- a/runtime/openjdkjvm/Android.bp
+++ b/runtime/openjdkjvm/Android.bp
@@ -19,7 +19,10 @@
host_supported: true,
srcs: ["OpenjdkJvm.cc"],
include_dirs: ["art/runtime"],
- shared_libs: ["libnativehelper"],
+ shared_libs: [
+ "libbase",
+ "libnativehelper"
+ ],
}
art_cc_library {
diff --git a/runtime/openjdkjvm/OpenjdkJvm.cc b/runtime/openjdkjvm/OpenjdkJvm.cc
index 54ec5d3..4a62ecd 100644
--- a/runtime/openjdkjvm/OpenjdkJvm.cc
+++ b/runtime/openjdkjvm/OpenjdkJvm.cc
@@ -61,10 +61,10 @@
#undef LOG_TAG
#define LOG_TAG "artopenjdk"
-using art::WARNING;
-using art::INFO;
-using art::ERROR;
-using art::FATAL;
+using ::android::base::WARNING;
+using ::android::base::INFO;
+using ::android::base::ERROR;
+using ::android::base::FATAL;
/* posix open() with extensions; used by e.g. ZipFile */
JNIEXPORT jint JVM_Open(const char* fname, jint flags, jint mode) {
diff --git a/runtime/openjdkjvmti/Android.bp b/runtime/openjdkjvmti/Android.bp
index 08272fa..d7a6c0a 100644
--- a/runtime/openjdkjvmti/Android.bp
+++ b/runtime/openjdkjvmti/Android.bp
@@ -20,7 +20,10 @@
srcs: ["OpenjdkJvmTi.cc",
"transform.cc"],
include_dirs: ["art/runtime"],
- shared_libs: ["libnativehelper"],
+ shared_libs: [
+ "libbase",
+ "libnativehelper",
+ ],
}
art_cc_library {
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index a0d79f3..b5622b5 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -201,8 +201,8 @@
art::Handle<art::mirror::Class> loader_class(hs.NewHandle(h_class_loader->GetClass()));
// Check if loader is a BaseDexClassLoader
if (!loader_class->IsSubClass(base_dex_loader_class.Get())) {
- LOG(art::ERROR) << "The classloader is not a BaseDexClassLoader which is currently the only "
- << "supported class loader type!";
+ LOG(ERROR) << "The classloader is not a BaseDexClassLoader which is currently the only "
+ << "supported class loader type!";
return false;
}
art::Handle<art::mirror::Object> path_list(
@@ -333,7 +333,7 @@
// Find dalvik.system.DexFile that represents the dex file we are changing.
if (!FindDalvikSystemDexFileAndLoaderForClass(klass, &dex_file_ptr, &class_loader_ptr)) {
self->TransitionFromRunnableToSuspended(old_state);
- LOG(art::ERROR) << "Could not find DexFile.";
+ LOG(ERROR) << "Could not find DexFile.";
return ERR(INTERNAL);
}
art::Handle<art::mirror::Object> dex_file_obj(hs.NewHandle(dex_file_ptr));
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index b3f29c2..9056d96 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -145,7 +145,7 @@
if (kDebugExceptionDelivery) {
mirror::String* msg = exception->GetDetailMessage();
std::string str_msg(msg != nullptr ? msg->ToModifiedUtf8() : "");
- self_->DumpStack(LOG(INFO) << "Delivering exception: " << PrettyTypeOf(exception)
+ self_->DumpStack(LOG_STREAM(INFO) << "Delivering exception: " << PrettyTypeOf(exception)
<< ": " << str_msg << "\n");
}
StackHandleScope<1> hs(self_);
@@ -218,7 +218,7 @@
DCHECK(handler_method_ != nullptr && handler_method_header_->IsOptimized());
if (kDebugExceptionDelivery) {
- self_->DumpStack(LOG(INFO) << "Setting catch phis: ");
+ self_->DumpStack(LOG_STREAM(INFO) << "Setting catch phis: ");
}
const size_t number_of_vregs = handler_method_->GetCodeItem()->registers_size_;
@@ -520,7 +520,7 @@
void QuickExceptionHandler::DeoptimizeStack() {
DCHECK(is_deoptimization_);
if (kDebugExceptionDelivery) {
- self_->DumpStack(LOG(INFO) << "Deoptimizing: ");
+ self_->DumpStack(LOG_STREAM(INFO) << "Deoptimizing: ");
}
DeoptimizeStackVisitor visitor(self_, context_, this, false);
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index c69e98c..30b10d8 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -455,7 +455,7 @@
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
// Replace calls to String.<init> with equivalent StringFactory call.
- method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ method = WellKnownClasses::StringInitToStringFactory(method);
}
mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
uint32_t shorty_len = 0;
@@ -486,7 +486,7 @@
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
// Replace calls to String.<init> with equivalent StringFactory call.
- method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ method = WellKnownClasses::StringInitToStringFactory(method);
}
mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
uint32_t shorty_len = 0;
@@ -518,7 +518,7 @@
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
// Replace calls to String.<init> with equivalent StringFactory call.
- method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ method = WellKnownClasses::StringInitToStringFactory(method);
receiver = nullptr;
}
uint32_t shorty_len = 0;
@@ -550,7 +550,7 @@
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
// Replace calls to String.<init> with equivalent StringFactory call.
- method = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ method = WellKnownClasses::StringInitToStringFactory(method);
receiver = nullptr;
}
uint32_t shorty_len = 0;
@@ -596,8 +596,7 @@
if (!m->IsStatic()) {
// Replace calls to String.<init> with equivalent StringFactory call.
if (declaring_class->IsStringClass() && m->IsConstructor()) {
- jmethodID mid = soa.EncodeMethod(m);
- m = soa.DecodeMethod(WellKnownClasses::StringInitToStringFactoryMethodID(mid));
+ m = WellKnownClasses::StringInitToStringFactory(m);
CHECK(javaReceiver == nullptr);
} else {
// Check that the receiver is non-null and an instance of the field's declaring class.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 2be3b52..5bb38f5 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -255,7 +255,7 @@
// This can't be called from the Heap destructor below because it
// could call RosAlloc::InspectAll() which needs the thread_list
// to be still alive.
- heap_->DumpGcPerformanceInfo(LOG(INFO));
+ heap_->DumpGcPerformanceInfo(LOG_STREAM(INFO));
}
Thread* self = Thread::Current();
@@ -433,14 +433,14 @@
// Many people have difficulty distinguish aborts from crashes,
// so be explicit.
AbortState state;
- LOG(INTERNAL_FATAL) << Dumpable<AbortState>(state);
+ LOG(FATAL_WITHOUT_ABORT) << Dumpable<AbortState>(state);
// Call the abort hook if we have one.
if (Runtime::Current() != nullptr && Runtime::Current()->abort_ != nullptr) {
- LOG(INTERNAL_FATAL) << "Calling abort hook...";
+ LOG(FATAL_WITHOUT_ABORT) << "Calling abort hook...";
Runtime::Current()->abort_();
// notreached
- LOG(INTERNAL_FATAL) << "Unexpectedly returned from abort hook!";
+ LOG(FATAL_WITHOUT_ABORT) << "Unexpectedly returned from abort hook!";
}
#if defined(__GLIBC__)
diff --git a/runtime/runtime_android.cc b/runtime/runtime_android.cc
index 33600dd..aed6a2b 100644
--- a/runtime/runtime_android.cc
+++ b/runtime/runtime_android.cc
@@ -34,7 +34,10 @@
void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_context) {
static bool handling_unexpected_signal = false;
if (handling_unexpected_signal) {
- LogMessage::LogLine(__FILE__, __LINE__, INTERNAL_FATAL, "HandleUnexpectedSignal reentered\n");
+ LogHelper::LogLineLowStack(__FILE__,
+ __LINE__,
+ ::android::base::FATAL_WITHOUT_ABORT,
+ "HandleUnexpectedSignal reentered\n");
_exit(1);
}
handling_unexpected_signal = true;
@@ -44,11 +47,11 @@
Runtime* runtime = Runtime::Current();
if (runtime != nullptr) {
// Print this out first in case DumpObject faults.
- LOG(INTERNAL_FATAL) << "Fault message: " << runtime->GetFaultMessage();
+ LOG(FATAL_WITHOUT_ABORT) << "Fault message: " << runtime->GetFaultMessage();
gc::Heap* heap = runtime->GetHeap();
if (kDumpHeapObjectOnSigsevg && heap != nullptr && info != nullptr) {
- LOG(INTERNAL_FATAL) << "Dump heap object at fault address: ";
- heap->DumpObject(LOG(INTERNAL_FATAL), reinterpret_cast<mirror::Object*>(info->si_addr));
+ LOG(FATAL_WITHOUT_ABORT) << "Dump heap object at fault address: ";
+ heap->DumpObject(LOG_STREAM(FATAL_WITHOUT_ABORT), reinterpret_cast<mirror::Object*>(info->si_addr));
}
}
// Run the old signal handler.
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index 60ebabc..cee73e1 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -309,7 +309,10 @@
void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_context) {
static bool handlingUnexpectedSignal = false;
if (handlingUnexpectedSignal) {
- LogMessage::LogLine(__FILE__, __LINE__, INTERNAL_FATAL, "HandleUnexpectedSignal reentered\n");
+ LogHelper::LogLineLowStack(__FILE__,
+ __LINE__,
+ ::android::base::FATAL_WITHOUT_ABORT,
+ "HandleUnexpectedSignal reentered\n");
if (IsTimeoutSignal(signal_number)) {
// Ignore a recursive timeout.
return;
@@ -334,7 +337,7 @@
UContext thread_context(raw_context);
Backtrace thread_backtrace(raw_context);
- LOG(INTERNAL_FATAL) << "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"
+ LOG(FATAL_WITHOUT_ABORT) << "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"
<< StringPrintf("Fatal signal %d (%s), code %d (%s)",
signal_number, GetSignalName(signal_number),
info->si_code,
@@ -346,7 +349,7 @@
<< "Registers:\n" << Dumpable<UContext>(thread_context) << "\n"
<< "Backtrace:\n" << Dumpable<Backtrace>(thread_backtrace);
if (kIsDebugBuild && signal_number == SIGSEGV) {
- PrintFileToLog("/proc/self/maps", LogSeverity::INTERNAL_FATAL);
+ PrintFileToLog("/proc/self/maps", LogSeverity::FATAL_WITHOUT_ABORT);
}
Runtime* runtime = Runtime::Current();
if (runtime != nullptr) {
@@ -354,17 +357,17 @@
// 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(LOG(INTERNAL_FATAL), kDumpNativeStackOnTimeout);
+ runtime->GetThreadList()->Dump(LOG_STREAM(FATAL_WITHOUT_ABORT), kDumpNativeStackOnTimeout);
}
gc::Heap* heap = runtime->GetHeap();
- LOG(INTERNAL_FATAL) << "Fault message: " << runtime->GetFaultMessage();
+ LOG(FATAL_WITHOUT_ABORT) << "Fault message: " << runtime->GetFaultMessage();
if (kDumpHeapObjectOnSigsevg && heap != nullptr && info != nullptr) {
- LOG(INTERNAL_FATAL) << "Dump heap object at fault address: ";
- heap->DumpObject(LOG(INTERNAL_FATAL), reinterpret_cast<mirror::Object*>(info->si_addr));
+ LOG(FATAL_WITHOUT_ABORT) << "Dump heap object at fault address: ";
+ heap->DumpObject(LOG_STREAM(FATAL_WITHOUT_ABORT), reinterpret_cast<mirror::Object*>(info->si_addr));
}
}
if (getenv("debug_db_uid") != nullptr || getenv("art_wait_for_gdb_on_crash") != nullptr) {
- LOG(INTERNAL_FATAL) << "********************************************************\n"
+ LOG(FATAL_WITHOUT_ABORT) << "********************************************************\n"
<< "* Process " << getpid() << " thread " << tid << " \"" << thread_name
<< "\""
<< " has been suspended while crashing.\n"
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index 6cb7950..848c0e3 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -172,7 +172,7 @@
LOG(INFO) << *self << ": reacting to signal " << signal_number;
// If anyone's holding locks (which might prevent us from getting back into state Runnable), say so...
- Runtime::Current()->DumpLockHolders(LOG(INFO));
+ Runtime::Current()->DumpLockHolders(LOG_STREAM(INFO));
}
return signal_number;
diff --git a/runtime/simulator/Android.bp b/runtime/simulator/Android.bp
index 49322fc..03e3f15 100644
--- a/runtime/simulator/Android.bp
+++ b/runtime/simulator/Android.bp
@@ -25,6 +25,7 @@
"code_simulator_arm64.cc",
],
shared_libs: [
+ "libbase",
"liblog",
],
cflags: ["-DVIXL_INCLUDE_SIMULATOR_AARCH64"],
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 8940354..d0ea2d7 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -127,43 +127,6 @@
InitEntryPoints(&tlsPtr_.jni_entrypoints, &tlsPtr_.quick_entrypoints);
}
-void Thread::InitStringEntryPoints() {
- ScopedObjectAccess soa(this);
- QuickEntryPoints* qpoints = &tlsPtr_.quick_entrypoints;
- qpoints->pNewEmptyString = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newEmptyString));
- qpoints->pNewStringFromBytes_B = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_B));
- qpoints->pNewStringFromBytes_BI = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BI));
- qpoints->pNewStringFromBytes_BII = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BII));
- qpoints->pNewStringFromBytes_BIII = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIII));
- qpoints->pNewStringFromBytes_BIIString = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIIString));
- qpoints->pNewStringFromBytes_BString = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BString));
- qpoints->pNewStringFromBytes_BIICharset = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIICharset));
- qpoints->pNewStringFromBytes_BCharset = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BCharset));
- qpoints->pNewStringFromChars_C = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromChars_C));
- qpoints->pNewStringFromChars_CII = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromChars_CII));
- qpoints->pNewStringFromChars_IIC = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromChars_IIC));
- qpoints->pNewStringFromCodePoints = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromCodePoints));
- qpoints->pNewStringFromString = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromString));
- qpoints->pNewStringFromStringBuffer = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromStringBuffer));
- qpoints->pNewStringFromStringBuilder = reinterpret_cast<void(*)()>(
- soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromStringBuilder));
-}
-
void Thread::ResetQuickAllocEntryPointsForThread() {
ResetQuickAllocEntryPoints(&tlsPtr_.quick_entrypoints);
}
@@ -609,7 +572,7 @@
}
VLOG(threads) << "Creating native thread for " << thread_name;
- self->Dump(LOG(INFO));
+ self->Dump(LOG_STREAM(INFO));
}
Runtime* runtime = Runtime::Current();
@@ -804,7 +767,7 @@
VLOG(threads) << "Attaching unnamed thread.";
}
ScopedObjectAccess soa(self);
- self->Dump(LOG(INFO));
+ self->Dump(LOG_STREAM(INFO));
}
{
@@ -911,8 +874,10 @@
+ 4 * KB;
if (read_stack_size <= min_stack) {
// Note, as we know the stack is small, avoid operations that could use a lot of stack.
- LogMessage::LogLineLowStack(__PRETTY_FUNCTION__, __LINE__, ERROR,
- "Attempt to attach a thread with a too-small stack");
+ LogHelper::LogLineLowStack(__PRETTY_FUNCTION__,
+ __LINE__,
+ ::android::base::ERROR,
+ "Attempt to attach a thread with a too-small stack");
return false;
}
@@ -2382,7 +2347,7 @@
ThrowNewException("Ljava/lang/OutOfMemoryError;", msg);
tls32_.throwing_OutOfMemoryError = false;
} else {
- Dump(LOG(WARNING)); // The pre-allocated OOME has no stack, so help out and log one.
+ Dump(LOG_STREAM(WARNING)); // The pre-allocated OOME has no stack, so help out and log one.
SetException(Runtime::Current()->GetPreAllocatedOutOfMemoryError());
}
}
@@ -2775,16 +2740,16 @@
bool failed = false;
if (!space->GetLiveBitmap()->Test(klass)) {
failed = true;
- LOG(INTERNAL_FATAL) << "Unmarked object in image " << *space;
+ LOG(FATAL_WITHOUT_ABORT) << "Unmarked object in image " << *space;
} else if (!heap->GetLiveBitmap()->Test(klass)) {
failed = true;
- LOG(INTERNAL_FATAL) << "Unmarked object in image through live bitmap " << *space;
+ LOG(FATAL_WITHOUT_ABORT) << "Unmarked object in image through live bitmap " << *space;
}
if (failed) {
- GetThread()->Dump(LOG(INTERNAL_FATAL));
- space->AsImageSpace()->DumpSections(LOG(INTERNAL_FATAL));
- LOG(INTERNAL_FATAL) << "Method@" << method->GetDexMethodIndex() << ":" << method
- << " klass@" << klass;
+ GetThread()->Dump(LOG_STREAM(FATAL_WITHOUT_ABORT));
+ space->AsImageSpace()->DumpSections(LOG_STREAM(FATAL_WITHOUT_ABORT));
+ LOG(FATAL_WITHOUT_ABORT) << "Method@" << method->GetDexMethodIndex() << ":" << method
+ << " klass@" << klass;
// Pretty info last in case it crashes.
LOG(FATAL) << "Method " << PrettyMethod(method) << " klass " << PrettyClass(klass);
}
@@ -2838,7 +2803,7 @@
if (kIsDebugBuild && ref_addr == nullptr) {
std::string thread_name;
GetThread()->GetThreadName(thread_name);
- LOG(INTERNAL_FATAL) << "On thread " << thread_name;
+ LOG(FATAL_WITHOUT_ABORT) << "On thread " << thread_name;
DescribeStack(GetThread());
LOG(FATAL) << "Found an unsaved callee-save register " << i << " (null GPRAddress) "
<< "set in register_mask=" << register_mask << " at " << DescribeLocation();
@@ -2953,7 +2918,7 @@
// However, we seem to have already extended to use the full stack.
LOG(ERROR) << "Need to increase kStackOverflowReservedBytes (currently "
<< GetStackOverflowReservedBytes(kRuntimeISA) << ")?";
- DumpStack(LOG(ERROR));
+ DumpStack(LOG_STREAM(ERROR));
LOG(FATAL) << "Recursive stack overflow.";
}
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 5e6c8a4..03b03de 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -214,7 +214,7 @@
bool timed_out = barrier_.Increment(self, threads_running_checkpoint, kDumpWaitTimeout);
if (timed_out) {
// Avoid a recursive abort.
- LOG((kIsDebugBuild && (gAborting == 0)) ? FATAL : ERROR)
+ LOG((kIsDebugBuild && (gAborting == 0)) ? ::android::base::FATAL : ::android::base::ERROR)
<< "Unexpected time out during dump checkpoint.";
}
}
@@ -628,7 +628,8 @@
// EAGAIN and EINTR both indicate a spurious failure, try again from the beginning.
if ((errno != EAGAIN) && (errno != EINTR)) {
if (errno == ETIMEDOUT) {
- LOG(kIsDebugBuild ? FATAL : ERROR) << "Unexpected time out during suspend all.";
+ LOG(kIsDebugBuild ? ::android::base::FATAL : ::android::base::ERROR)
+ << "Unexpected time out during suspend all.";
} else {
PLOG(FATAL) << "futex wait failed for SuspendAllInternal()";
}
@@ -775,7 +776,10 @@
// ThreadList::WaitForOtherNonDaemonThreadsToExit.
suspended_thread->ModifySuspendCount(soa.Self(), -1, nullptr, debug_suspension);
}
- ThreadSuspendByPeerWarning(self, WARNING, "No such thread for suspend", peer);
+ ThreadSuspendByPeerWarning(self,
+ ::android::base::WARNING,
+ "No such thread for suspend",
+ peer);
return nullptr;
}
if (!Contains(thread)) {
@@ -822,7 +826,10 @@
}
const uint64_t total_delay = NanoTime() - start_time;
if (total_delay >= MsToNs(kThreadSuspendTimeoutMs)) {
- ThreadSuspendByPeerWarning(self, FATAL, "Thread suspension timed out", peer);
+ ThreadSuspendByPeerWarning(self,
+ ::android::base::FATAL,
+ "Thread suspension timed out",
+ peer);
if (suspended_thread != nullptr) {
CHECK_EQ(suspended_thread, thread);
suspended_thread->ModifySuspendCount(soa.Self(), -1, nullptr, debug_suspension);
@@ -882,7 +889,9 @@
CHECK(suspended_thread == nullptr) << "Suspended thread " << suspended_thread
<< " no longer in thread list";
// There's a race in inflating a lock and the owner giving up ownership and then dying.
- ThreadSuspendByThreadIdWarning(WARNING, "No such thread id for suspend", thread_id);
+ ThreadSuspendByThreadIdWarning(::android::base::WARNING,
+ "No such thread id for suspend",
+ thread_id);
return nullptr;
}
VLOG(threads) << "SuspendThreadByThreadId found thread: " << *thread;
@@ -923,7 +932,9 @@
}
const uint64_t total_delay = NanoTime() - start_time;
if (total_delay >= MsToNs(kThreadSuspendTimeoutMs)) {
- ThreadSuspendByThreadIdWarning(WARNING, "Thread suspension timed out", thread_id);
+ ThreadSuspendByThreadIdWarning(::android::base::WARNING,
+ "Thread suspension timed out",
+ thread_id);
if (suspended_thread != nullptr) {
thread->ModifySuspendCount(soa.Self(), -1, nullptr, debug_suspension);
}
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index abd741c..13ef043 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -434,14 +434,15 @@
severity = LogSeverity::WARNING;
break;
case HardFailLogMode::kLogInternalFatal:
- severity = LogSeverity::INTERNAL_FATAL;
+ severity = LogSeverity::FATAL_WITHOUT_ABORT;
break;
default:
LOG(FATAL) << "Unsupported log-level " << static_cast<uint32_t>(log_level);
UNREACHABLE();
}
- verifier.DumpFailures(LOG(severity) << "Verification error in "
- << PrettyMethod(method_idx, *dex_file) << "\n");
+ verifier.DumpFailures(LOG_STREAM(severity) << "Verification error in "
+ << PrettyMethod(method_idx, *dex_file)
+ << "\n");
}
if (hard_failure_msg != nullptr) {
CHECK(!verifier.failure_messages_.empty());
diff --git a/runtime/verifier/verifier_log_mode.h b/runtime/verifier/verifier_log_mode.h
index 3744b9b..e83d174 100644
--- a/runtime/verifier/verifier_log_mode.h
+++ b/runtime/verifier/verifier_log_mode.h
@@ -24,7 +24,7 @@
kLogNone, // Don't log hard failures at all.
kLogVerbose, // Log with severity VERBOSE.
kLogWarning, // Log with severity WARNING.
- kLogInternalFatal, // Log with severity INTERNAL_FATAL
+ kLogInternalFatal, // Log with severity FATAL_WITHOUT_ABORT
};
} // namespace verifier
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 16c7f77..6b569f4 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -21,6 +21,7 @@
#include <sstream>
#include "base/logging.h"
+#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "mirror/class.h"
#include "mirror/throwable.h"
#include "ScopedLocalRef.h"
@@ -89,38 +90,6 @@
jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke;
jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad;
jmethodID WellKnownClasses::java_lang_Short_valueOf;
-jmethodID WellKnownClasses::java_lang_String_init;
-jmethodID WellKnownClasses::java_lang_String_init_B;
-jmethodID WellKnownClasses::java_lang_String_init_BI;
-jmethodID WellKnownClasses::java_lang_String_init_BII;
-jmethodID WellKnownClasses::java_lang_String_init_BIII;
-jmethodID WellKnownClasses::java_lang_String_init_BIIString;
-jmethodID WellKnownClasses::java_lang_String_init_BString;
-jmethodID WellKnownClasses::java_lang_String_init_BIICharset;
-jmethodID WellKnownClasses::java_lang_String_init_BCharset;
-jmethodID WellKnownClasses::java_lang_String_init_C;
-jmethodID WellKnownClasses::java_lang_String_init_CII;
-jmethodID WellKnownClasses::java_lang_String_init_IIC;
-jmethodID WellKnownClasses::java_lang_String_init_String;
-jmethodID WellKnownClasses::java_lang_String_init_StringBuffer;
-jmethodID WellKnownClasses::java_lang_String_init_III;
-jmethodID WellKnownClasses::java_lang_String_init_StringBuilder;
-jmethodID WellKnownClasses::java_lang_StringFactory_newEmptyString;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_B;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BI;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BII;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIII;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIIString;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BString;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIICharset;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BCharset;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromChars_C;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromChars_CII;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromChars_IIC;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromString;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromStringBuffer;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromCodePoints;
-jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromStringBuilder;
jmethodID WellKnownClasses::java_lang_System_runFinalization = nullptr;
jmethodID WellKnownClasses::java_lang_Thread_dispatchUncaughtException;
jmethodID WellKnownClasses::java_lang_Thread_init;
@@ -182,7 +151,7 @@
if (fid == nullptr) {
ScopedObjectAccess soa(env);
if (soa.Self()->IsExceptionPending()) {
- LOG(INTERNAL_FATAL) << soa.Self()->GetException()->Dump();
+ LOG(FATAL_WITHOUT_ABORT) << soa.Self()->GetException()->Dump();
}
std::ostringstream os;
WellKnownClasses::ToClass(c)->DumpClass(os, mirror::Class::kDumpClassFullDetail);
@@ -199,7 +168,7 @@
if (mid == nullptr) {
ScopedObjectAccess soa(env);
if (soa.Self()->IsExceptionPending()) {
- LOG(INTERNAL_FATAL) << soa.Self()->GetException()->Dump();
+ LOG(FATAL_WITHOUT_ABORT) << soa.Self()->GetException()->Dump();
}
std::ostringstream os;
WellKnownClasses::ToClass(c)->DumpClass(os, mirror::Class::kDumpClassFullDetail);
@@ -215,6 +184,76 @@
StringPrintf("(%c)L%s;", prim_name, boxed_name).c_str());
}
+#define STRING_INIT_LIST(V) \
+ V(java_lang_String_init, "()V", newEmptyString, "newEmptyString", "()Ljava/lang/String;", NewEmptyString) \
+ V(java_lang_String_init_B, "([B)V", newStringFromBytes_B, "newStringFromBytes", "([B)Ljava/lang/String;", NewStringFromBytes_B) \
+ V(java_lang_String_init_BI, "([BI)V", newStringFromBytes_BI, "newStringFromBytes", "([BI)Ljava/lang/String;", NewStringFromBytes_BI) \
+ V(java_lang_String_init_BII, "([BII)V", newStringFromBytes_BII, "newStringFromBytes", "([BII)Ljava/lang/String;", NewStringFromBytes_BII) \
+ V(java_lang_String_init_BIII, "([BIII)V", newStringFromBytes_BIII, "newStringFromBytes", "([BIII)Ljava/lang/String;", NewStringFromBytes_BIII) \
+ V(java_lang_String_init_BIIString, "([BIILjava/lang/String;)V", newStringFromBytes_BIIString, "newStringFromBytes", "([BIILjava/lang/String;)Ljava/lang/String;", NewStringFromBytes_BIIString) \
+ V(java_lang_String_init_BString, "([BLjava/lang/String;)V", newStringFromBytes_BString, "newStringFromBytes", "([BLjava/lang/String;)Ljava/lang/String;", NewStringFromBytes_BString) \
+ V(java_lang_String_init_BIICharset, "([BIILjava/nio/charset/Charset;)V", newStringFromBytes_BIICharset, "newStringFromBytes", "([BIILjava/nio/charset/Charset;)Ljava/lang/String;", NewStringFromBytes_BIICharset) \
+ V(java_lang_String_init_BCharset, "([BLjava/nio/charset/Charset;)V", newStringFromBytes_BCharset, "newStringFromBytes", "([BLjava/nio/charset/Charset;)Ljava/lang/String;", NewStringFromBytes_BCharset) \
+ V(java_lang_String_init_C, "([C)V", newStringFromChars_C, "newStringFromChars", "([C)Ljava/lang/String;", NewStringFromChars_C) \
+ V(java_lang_String_init_CII, "([CII)V", newStringFromChars_CII, "newStringFromChars", "([CII)Ljava/lang/String;", NewStringFromChars_CII) \
+ V(java_lang_String_init_IIC, "(II[C)V", newStringFromChars_IIC, "newStringFromChars", "(II[C)Ljava/lang/String;", NewStringFromChars_IIC) \
+ V(java_lang_String_init_String, "(Ljava/lang/String;)V", newStringFromString, "newStringFromString", "(Ljava/lang/String;)Ljava/lang/String;", NewStringFromString) \
+ V(java_lang_String_init_StringBuffer, "(Ljava/lang/StringBuffer;)V", newStringFromStringBuffer, "newStringFromStringBuffer", "(Ljava/lang/StringBuffer;)Ljava/lang/String;", NewStringFromStringBuffer) \
+ V(java_lang_String_init_III, "([III)V", newStringFromCodePoints, "newStringFromCodePoints", "([III)Ljava/lang/String;", NewStringFromCodePoints) \
+ V(java_lang_String_init_StringBuilder, "(Ljava/lang/StringBuilder;)V", newStringFromStringBuilder, "newStringFromStringBuilder", "(Ljava/lang/StringBuilder;)Ljava/lang/String;", NewStringFromStringBuilder) \
+
+#define STATIC_STRING_INIT(init_runtime_name, init_signature, new_runtime_name, ...) \
+ static ArtMethod* init_runtime_name; \
+ static ArtMethod* new_runtime_name;
+ STRING_INIT_LIST(STATIC_STRING_INIT)
+#undef STATIC_STRING_INIT
+
+void WellKnownClasses::InitStringInit(JNIEnv* env) {
+ ScopedObjectAccess soa(Thread::Current());
+ #define LOAD_STRING_INIT(init_runtime_name, init_signature, new_runtime_name, \
+ new_java_name, new_signature, ...) \
+ init_runtime_name = soa.DecodeMethod( \
+ CacheMethod(env, java_lang_String, false, "<init>", init_signature)); \
+ new_runtime_name = soa.DecodeMethod( \
+ CacheMethod(env, java_lang_StringFactory, true, new_java_name, new_signature));
+ STRING_INIT_LIST(LOAD_STRING_INIT)
+ #undef LOAD_STRING_INIT
+}
+
+void Thread::InitStringEntryPoints() {
+ QuickEntryPoints* qpoints = &tlsPtr_.quick_entrypoints;
+ #define SET_ENTRY_POINT(init_runtime_name, init_signature, new_runtime_name, \
+ new_java_name, new_signature, entry_point_name) \
+ qpoints->p ## entry_point_name = reinterpret_cast<void(*)()>(new_runtime_name);
+ STRING_INIT_LIST(SET_ENTRY_POINT)
+ #undef SET_ENTRY_POINT
+}
+
+ArtMethod* WellKnownClasses::StringInitToStringFactory(ArtMethod* string_init) {
+ #define TO_STRING_FACTORY(init_runtime_name, init_signature, new_runtime_name, \
+ new_java_name, new_signature, entry_point_name) \
+ if (string_init == init_runtime_name) { \
+ return new_runtime_name; \
+ }
+ STRING_INIT_LIST(TO_STRING_FACTORY)
+ #undef TO_STRING_FACTORY
+ LOG(FATAL) << "Could not find StringFactory method for String.<init>";
+ return nullptr;
+}
+
+uint32_t WellKnownClasses::StringInitToEntryPoint(ArtMethod* string_init) {
+ #define TO_ENTRY_POINT(init_runtime_name, init_signature, new_runtime_name, \
+ new_java_name, new_signature, entry_point_name) \
+ if (string_init == init_runtime_name) { \
+ return kQuick ## entry_point_name; \
+ }
+ STRING_INIT_LIST(TO_ENTRY_POINT)
+ #undef TO_STRING_FACTORY
+ LOG(FATAL) << "Could not find StringFactory method for String.<init>";
+ return 0;
+}
+#undef STRING_INIT_LIST
+
void WellKnownClasses::Init(JNIEnv* env) {
com_android_dex_Dex = CacheClass(env, "com/android/dex/Dex");
dalvik_annotation_optimization_CriticalNative =
@@ -284,62 +323,6 @@
org_apache_harmony_dalvik_ddmc_DdmServer_broadcast = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "broadcast", "(I)V");
org_apache_harmony_dalvik_ddmc_DdmServer_dispatch = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;");
- java_lang_String_init = CacheMethod(env, java_lang_String, false, "<init>", "()V");
- java_lang_String_init_B = CacheMethod(env, java_lang_String, false, "<init>", "([B)V");
- java_lang_String_init_BI = CacheMethod(env, java_lang_String, false, "<init>", "([BI)V");
- java_lang_String_init_BII = CacheMethod(env, java_lang_String, false, "<init>", "([BII)V");
- java_lang_String_init_BIII = CacheMethod(env, java_lang_String, false, "<init>", "([BIII)V");
- java_lang_String_init_BIIString = CacheMethod(env, java_lang_String, false, "<init>",
- "([BIILjava/lang/String;)V");
- java_lang_String_init_BString = CacheMethod(env, java_lang_String, false, "<init>",
- "([BLjava/lang/String;)V");
- java_lang_String_init_BIICharset = CacheMethod(env, java_lang_String, false, "<init>",
- "([BIILjava/nio/charset/Charset;)V");
- java_lang_String_init_BCharset = CacheMethod(env, java_lang_String, false, "<init>",
- "([BLjava/nio/charset/Charset;)V");
- java_lang_String_init_C = CacheMethod(env, java_lang_String, false, "<init>", "([C)V");
- java_lang_String_init_CII = CacheMethod(env, java_lang_String, false, "<init>", "([CII)V");
- java_lang_String_init_IIC = CacheMethod(env, java_lang_String, false, "<init>", "(II[C)V");
- java_lang_String_init_String = CacheMethod(env, java_lang_String, false, "<init>",
- "(Ljava/lang/String;)V");
- java_lang_String_init_StringBuffer = CacheMethod(env, java_lang_String, false, "<init>",
- "(Ljava/lang/StringBuffer;)V");
- java_lang_String_init_III = CacheMethod(env, java_lang_String, false, "<init>", "([III)V");
- java_lang_String_init_StringBuilder = CacheMethod(env, java_lang_String, false, "<init>",
- "(Ljava/lang/StringBuilder;)V");
- java_lang_StringFactory_newEmptyString = CacheMethod(env, java_lang_StringFactory, true,
- "newEmptyString", "()Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_B = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromBytes", "([B)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BI = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromBytes", "([BI)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BII = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromBytes", "([BII)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BIII = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromBytes", "([BIII)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BIIString = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromBytes", "([BIILjava/lang/String;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BString = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromBytes", "([BLjava/lang/String;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BIICharset = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromBytes", "([BIILjava/nio/charset/Charset;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromBytes_BCharset = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromBytes", "([BLjava/nio/charset/Charset;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromChars_C = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromChars", "([C)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromChars_CII = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromChars", "([CII)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromChars_IIC = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromChars", "(II[C)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromString = CacheMethod(env, java_lang_StringFactory, true,
- "newStringFromString", "(Ljava/lang/String;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromStringBuffer = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromStringBuffer", "(Ljava/lang/StringBuffer;)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromCodePoints = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromCodePoints", "([III)Ljava/lang/String;");
- java_lang_StringFactory_newStringFromStringBuilder = CacheMethod(env, java_lang_StringFactory,
- true, "newStringFromStringBuilder", "(Ljava/lang/StringBuilder;)Ljava/lang/String;");
-
dalvik_system_DexFile_cookie = CacheField(env, dalvik_system_DexFile, false, "mCookie", "Ljava/lang/Object;");
dalvik_system_DexFile_fileName = CacheField(env, dalvik_system_DexFile, false, "mFileName", "Ljava/lang/String;");
dalvik_system_PathClassLoader_pathList = CacheField(env, dalvik_system_PathClassLoader, false, "pathList", "Ldalvik/system/DexPathList;");
@@ -384,6 +367,7 @@
java_lang_Long_valueOf = CachePrimitiveBoxingMethod(env, 'J', "java/lang/Long");
java_lang_Short_valueOf = CachePrimitiveBoxingMethod(env, 'S', "java/lang/Short");
+ InitStringInit(env);
Thread::Current()->InitStringEntryPoints();
}
@@ -399,43 +383,4 @@
return reinterpret_cast<mirror::Class*>(Thread::Current()->DecodeJObject(global_jclass));
}
-jmethodID WellKnownClasses::StringInitToStringFactoryMethodID(jmethodID string_init) {
- // TODO: Prioritize ordering.
- if (string_init == java_lang_String_init) {
- return java_lang_StringFactory_newEmptyString;
- } else if (string_init == java_lang_String_init_B) {
- return java_lang_StringFactory_newStringFromBytes_B;
- } else if (string_init == java_lang_String_init_BI) {
- return java_lang_StringFactory_newStringFromBytes_BI;
- } else if (string_init == java_lang_String_init_BII) {
- return java_lang_StringFactory_newStringFromBytes_BII;
- } else if (string_init == java_lang_String_init_BIII) {
- return java_lang_StringFactory_newStringFromBytes_BIII;
- } else if (string_init == java_lang_String_init_BIIString) {
- return java_lang_StringFactory_newStringFromBytes_BIIString;
- } else if (string_init == java_lang_String_init_BString) {
- return java_lang_StringFactory_newStringFromBytes_BString;
- } else if (string_init == java_lang_String_init_BIICharset) {
- return java_lang_StringFactory_newStringFromBytes_BIICharset;
- } else if (string_init == java_lang_String_init_BCharset) {
- return java_lang_StringFactory_newStringFromBytes_BCharset;
- } else if (string_init == java_lang_String_init_C) {
- return java_lang_StringFactory_newStringFromChars_C;
- } else if (string_init == java_lang_String_init_CII) {
- return java_lang_StringFactory_newStringFromChars_CII;
- } else if (string_init == java_lang_String_init_IIC) {
- return java_lang_StringFactory_newStringFromChars_IIC;
- } else if (string_init == java_lang_String_init_String) {
- return java_lang_StringFactory_newStringFromString;
- } else if (string_init == java_lang_String_init_StringBuffer) {
- return java_lang_StringFactory_newStringFromStringBuffer;
- } else if (string_init == java_lang_String_init_III) {
- return java_lang_StringFactory_newStringFromCodePoints;
- } else if (string_init == java_lang_String_init_StringBuilder) {
- return java_lang_StringFactory_newStringFromStringBuilder;
- }
- LOG(FATAL) << "Could not find StringFactory method for String.<init>";
- return nullptr;
-}
-
} // namespace art
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index b4d179c..c9110e6 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -21,6 +21,9 @@
#include "jni.h"
namespace art {
+
+class ArtMethod;
+
namespace mirror {
class Class;
} // namespace mirror
@@ -35,7 +38,8 @@
public:
static void Init(JNIEnv* env); // Run before native methods are registered.
static void LateInit(JNIEnv* env); // Run after native methods are registered.
- static jmethodID StringInitToStringFactoryMethodID(jmethodID string_init);
+ static ArtMethod* StringInitToStringFactory(ArtMethod* method);
+ static uint32_t StringInitToEntryPoint(ArtMethod* method);
static mirror::Class* ToClass(jclass global_jclass)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -100,38 +104,6 @@
static jmethodID java_lang_reflect_Proxy_invoke;
static jmethodID java_lang_Runtime_nativeLoad;
static jmethodID java_lang_Short_valueOf;
- static jmethodID java_lang_String_init;
- static jmethodID java_lang_String_init_B;
- static jmethodID java_lang_String_init_BI;
- static jmethodID java_lang_String_init_BII;
- static jmethodID java_lang_String_init_BIII;
- static jmethodID java_lang_String_init_BIIString;
- static jmethodID java_lang_String_init_BString;
- static jmethodID java_lang_String_init_BIICharset;
- static jmethodID java_lang_String_init_BCharset;
- static jmethodID java_lang_String_init_C;
- static jmethodID java_lang_String_init_CII;
- static jmethodID java_lang_String_init_IIC;
- static jmethodID java_lang_String_init_String;
- static jmethodID java_lang_String_init_StringBuffer;
- static jmethodID java_lang_String_init_III;
- static jmethodID java_lang_String_init_StringBuilder;
- static jmethodID java_lang_StringFactory_newEmptyString;
- static jmethodID java_lang_StringFactory_newStringFromBytes_B;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BI;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BII;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BIII;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BIIString;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BString;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BIICharset;
- static jmethodID java_lang_StringFactory_newStringFromBytes_BCharset;
- static jmethodID java_lang_StringFactory_newStringFromChars_C;
- static jmethodID java_lang_StringFactory_newStringFromChars_CII;
- static jmethodID java_lang_StringFactory_newStringFromChars_IIC;
- static jmethodID java_lang_StringFactory_newStringFromString;
- static jmethodID java_lang_StringFactory_newStringFromStringBuffer;
- static jmethodID java_lang_StringFactory_newStringFromCodePoints;
- static jmethodID java_lang_StringFactory_newStringFromStringBuilder;
static jmethodID java_lang_System_runFinalization;
static jmethodID java_lang_Thread_dispatchUncaughtException;
static jmethodID java_lang_Thread_init;
@@ -177,6 +149,9 @@
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_length;
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_offset;
static jfieldID org_apache_harmony_dalvik_ddmc_Chunk_type;
+
+ private:
+ static void InitStringInit(JNIEnv* env);
};
} // namespace art
diff --git a/test/099-vmdebug/check b/test/099-vmdebug/check
index 57111bc..d124ce8 100755
--- a/test/099-vmdebug/check
+++ b/test/099-vmdebug/check
@@ -15,6 +15,6 @@
# limitations under the License.
# Strip the process pids and line numbers from exact error messages.
-sed -e '/^art E.*\] /d' "$2" > "$2.tmp"
+sed -e '/^dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/118-noimage-dex2oat/check b/test/118-noimage-dex2oat/check
index 57111bc..4f46083 100755
--- a/test/118-noimage-dex2oat/check
+++ b/test/118-noimage-dex2oat/check
@@ -15,6 +15,6 @@
# limitations under the License.
# Strip the process pids and line numbers from exact error messages.
-sed -e '/^art E.*\] /d' "$2" > "$2.tmp"
+sed -e '/^dalvikvm.* E.*\] /d' "$2" > "$2.tmp"
diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/119-noimage-patchoat/check b/test/119-noimage-patchoat/check
index 57111bc..d124ce8 100755
--- a/test/119-noimage-patchoat/check
+++ b/test/119-noimage-patchoat/check
@@ -15,6 +15,6 @@
# limitations under the License.
# Strip the process pids and line numbers from exact error messages.
-sed -e '/^art E.*\] /d' "$2" > "$2.tmp"
+sed -e '/^dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index 9f1499e..113b35f 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -91,7 +91,7 @@
static void MoreErrorInfo(pid_t pid, bool sig_quit_on_fail) {
printf("Secondary pid is %d\n", pid);
- PrintFileToLog(StringPrintf("/proc/%d/maps", pid), ERROR);
+ PrintFileToLog(StringPrintf("/proc/%d/maps", pid), ::android::base::ERROR);
if (sig_quit_on_fail) {
int res = kill(pid, SIGQUIT);
diff --git a/test/143-string-value/check b/test/143-string-value/check
index 92f6e90..2a3476c 100755
--- a/test/143-string-value/check
+++ b/test/143-string-value/check
@@ -15,6 +15,6 @@
# limitations under the License.
# Strip error log messages.
-sed -e '/^art E.*\] /d' "$2" > "$2.tmp"
+sed -e '/^dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/149-suspend-all-stress/suspend_all.cc b/test/149-suspend-all-stress/suspend_all.cc
index dfd944a..c1c0ff9 100644
--- a/test/149-suspend-all-stress/suspend_all.cc
+++ b/test/149-suspend-all-stress/suspend_all.cc
@@ -42,14 +42,16 @@
break;
}
case kOPDumpStack: {
- Runtime::Current()->GetThreadList()->Dump(LOG(INFO));
+ Runtime::Current()->GetThreadList()->Dump(LOG_STREAM(INFO));
usleep(500);
break;
}
case kOPSuspendAllDumpStack: {
// Not yet supported.
- // ScopedSuspendAll ssa(__FUNCTION__);
- // Runtime::Current()->GetThreadList()->Dump(LOG(INFO));
+ if ((false)) {
+ ScopedSuspendAll ssa(__FUNCTION__);
+ Runtime::Current()->GetThreadList()->Dump(LOG_STREAM(INFO));
+ }
break;
}
case kOPNumber:
diff --git a/test/Android.bp b/test/Android.bp
index 2d61000..72dcbba 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -63,6 +63,7 @@
"libvixld-arm64",
"libart-gtest",
+ "libbase",
"libicuuc",
"libicui18n",
"libnativehelper",
@@ -204,6 +205,7 @@
],
shared_libs: [
"libbacktrace",
+ "libbase",
"libnativehelper",
],
target: {
@@ -246,6 +248,7 @@
],
shared_libs: [
"libart",
+ "libbase",
"libopenjdkjvmti",
],
}
@@ -306,6 +309,7 @@
],
shared_libs: [
"libbacktrace",
+ "libbase",
"libnativehelper",
],
target: {
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index 4003ee0..ebf087d 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -73,7 +73,7 @@
$(ART_HOST_EXECUTABLES) \
$(ART_HOST_SHARED_LIBRARY_DEPENDENCIES) \
$(HOST_OUT_EXECUTABLES)/art \
- $(HOST_CORE_IMG_OUT_BASE)-optimizing-pic$(CORE_IMG_SUFFIX)
+ $(HOST_CORE_IMG_OUT_BASE)$(CORE_IMG_SUFFIX)
$(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_ART := $(HOST_OUT_EXECUTABLES)/art
$(AHAT_TEST_DUMP_HPROF): PRIVATE_AHAT_TEST_DUMP_JAR := $(AHAT_TEST_DUMP_JAR)
diff --git a/tools/ahat/README.txt b/tools/ahat/README.txt
index ecf9e53..8604ff0 100644
--- a/tools/ahat/README.txt
+++ b/tools/ahat/README.txt
@@ -9,7 +9,6 @@
Serve pages on the given port. Defaults to 7100.
TODO:
- * Show GC Root paths.
* Have a way to diff two heap dumps.
* Add more tips to the help page.
@@ -76,6 +75,7 @@
Release History:
0.8 Pending
+ Show sample path from GC root with field names in place of dominator path.
0.7 Aug 16, 2016
Launch ahat server before processing the heap dump.
diff --git a/tools/ahat/src/HeapTable.java b/tools/ahat/src/HeapTable.java
index ed11d17..5b84048 100644
--- a/tools/ahat/src/HeapTable.java
+++ b/tools/ahat/src/HeapTable.java
@@ -84,10 +84,10 @@
for (Heap heap : heaps) {
long size = config.getSize(elem, heap);
total += size;
- vals.add(DocString.format("%,14d", size));
+ vals.add(size == 0 ? DocString.text("") : DocString.format("%,14d", size));
}
if (showTotal) {
- vals.add(DocString.format("%,14d", total));
+ vals.add(total == 0 ? DocString.text("") : DocString.format("%,14d", total));
}
for (ValueConfig<T> value : values) {
diff --git a/tools/ahat/src/InstanceUtils.java b/tools/ahat/src/InstanceUtils.java
index 8769d11..94934a2 100644
--- a/tools/ahat/src/InstanceUtils.java
+++ b/tools/ahat/src/InstanceUtils.java
@@ -19,11 +19,17 @@
import com.android.tools.perflib.heap.ArrayInstance;
import com.android.tools.perflib.heap.ClassInstance;
import com.android.tools.perflib.heap.ClassObj;
+import com.android.tools.perflib.heap.Field;
import com.android.tools.perflib.heap.Heap;
import com.android.tools.perflib.heap.Instance;
+import com.android.tools.perflib.heap.RootObj;
import com.android.tools.perflib.heap.Type;
import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
/**
* Utilities for extracting information from hprof instances.
@@ -179,7 +185,7 @@
* Read a reference field of an instance.
* Returns null if the field value is null, or if the field couldn't be read.
*/
- private static Instance getRefField(Instance inst, String fieldName) {
+ public static Instance getRefField(Instance inst, String fieldName) {
Object value = getField(inst, fieldName);
if (!(value instanceof Instance)) {
return null;
@@ -357,4 +363,90 @@
}
return new NativeAllocation(size, inst.getHeap(), pointer, referent);
}
+
+ public static class PathElement {
+ public final Instance instance;
+ public final String field;
+ public boolean isDominator;
+
+ public PathElement(Instance instance, String field) {
+ this.instance = instance;
+ this.field = field;
+ this.isDominator = false;
+ }
+ }
+
+ /**
+ * Returns a sample path from a GC root to this instance.
+ * The given instance is included as the last element of the path with an
+ * empty field description.
+ */
+ public static List<PathElement> getPathFromGcRoot(Instance inst) {
+ List<PathElement> path = new ArrayList<PathElement>();
+
+ Instance dom = inst;
+ for (PathElement elem = new PathElement(inst, ""); elem != null;
+ elem = getNextPathElementToGcRoot(elem.instance)) {
+ if (elem.instance == dom) {
+ elem.isDominator = true;
+ dom = dom.getImmediateDominator();
+ }
+ path.add(elem);
+ }
+ Collections.reverse(path);
+ return path;
+ }
+
+ /**
+ * Returns the next instance to GC root from this object and a string
+ * description of which field of that object refers to the given instance.
+ * Returns null if the given instance has no next instance to the gc root.
+ */
+ private static PathElement getNextPathElementToGcRoot(Instance inst) {
+ Instance parent = inst.getNextInstanceToGcRoot();
+ if (parent == null || parent instanceof RootObj) {
+ return null;
+ }
+
+ // Search the parent for the reference to the child.
+ // TODO: This seems terribly inefficient. Can we use data structures to
+ // help us here?
+ String description = ".???";
+ if (parent instanceof ArrayInstance) {
+ ArrayInstance array = (ArrayInstance)parent;
+ Object[] values = array.getValues();
+ for (int i = 0; i < values.length; i++) {
+ if (values[i] instanceof Instance) {
+ Instance ref = (Instance)values[i];
+ if (ref.getId() == inst.getId()) {
+ description = String.format("[%d]", i);
+ break;
+ }
+ }
+ }
+ } else if (parent instanceof ClassObj) {
+ ClassObj cls = (ClassObj)parent;
+ for (Map.Entry<Field, Object> entries : cls.getStaticFieldValues().entrySet()) {
+ if (entries.getValue() instanceof Instance) {
+ Instance ref = (Instance)entries.getValue();
+ if (ref.getId() == inst.getId()) {
+ description = "." + entries.getKey().getName();
+ break;
+ }
+ }
+ }
+ } else if (parent instanceof ClassInstance) {
+ ClassInstance obj = (ClassInstance)parent;
+ for (ClassInstance.FieldValue fields : obj.getValues()) {
+ if (fields.getValue() instanceof Instance) {
+ Instance ref = (Instance)fields.getValue();
+ if (ref.getId() == inst.getId()) {
+ description = "." + fields.getField().getName();
+ break;
+ }
+ }
+ }
+ }
+ return new PathElement(parent, description);
+ }
}
diff --git a/tools/ahat/src/ObjectHandler.java b/tools/ahat/src/ObjectHandler.java
index 4df1be5..78aac17 100644
--- a/tools/ahat/src/ObjectHandler.java
+++ b/tools/ahat/src/ObjectHandler.java
@@ -22,7 +22,6 @@
import com.android.tools.perflib.heap.Field;
import com.android.tools.perflib.heap.Heap;
import com.android.tools.perflib.heap.Instance;
-import com.android.tools.perflib.heap.RootObj;
import com.android.tools.perflib.heap.RootType;
import java.io.IOException;
import java.util.ArrayList;
@@ -32,6 +31,8 @@
import java.util.List;
import java.util.Map;
+import static com.android.ahat.InstanceUtils.PathElement;
+
class ObjectHandler implements AhatHandler {
private static final String ARRAY_ELEMENTS_ID = "elements";
@@ -62,7 +63,7 @@
doc.big(Value.render(mSnapshot, inst));
printAllocationSite(doc, query, inst);
- printDominatorPath(doc, query, inst);
+ printGcRootPath(doc, query, inst);
doc.section("Object Info");
ClassObj cls = inst.getClassObj();
@@ -202,43 +203,43 @@
}
}
- private void printDominatorPath(Doc doc, Query query, Instance inst) {
- doc.section("Dominator Path from Root");
- List<Instance> path = new ArrayList<Instance>();
- for (Instance parent = inst;
- parent != null && !(parent instanceof RootObj);
- parent = parent.getImmediateDominator()) {
- path.add(parent);
- }
+ private void printGcRootPath(Doc doc, Query query, Instance inst) {
+ doc.section("Sample Path from GC Root");
+ List<PathElement> path = InstanceUtils.getPathFromGcRoot(inst);
// Add 'null' as a marker for the root.
- path.add(null);
- Collections.reverse(path);
+ path.add(0, null);
- HeapTable.TableConfig<Instance> table = new HeapTable.TableConfig<Instance>() {
+ HeapTable.TableConfig<PathElement> table = new HeapTable.TableConfig<PathElement>() {
public String getHeapsDescription() {
- return "Bytes Retained by Heap";
+ return "Bytes Retained by Heap (Dominators Only)";
}
- public long getSize(Instance element, Heap heap) {
+ public long getSize(PathElement element, Heap heap) {
if (element == null) {
return mSnapshot.getHeapSize(heap);
}
- int index = mSnapshot.getHeapIndex(heap);
- return element.getRetainedSize(index);
+ if (element.isDominator) {
+ int index = mSnapshot.getHeapIndex(heap);
+ return element.instance.getRetainedSize(index);
+ }
+ return 0;
}
- public List<HeapTable.ValueConfig<Instance>> getValueConfigs() {
- HeapTable.ValueConfig<Instance> value = new HeapTable.ValueConfig<Instance>() {
+ public List<HeapTable.ValueConfig<PathElement>> getValueConfigs() {
+ HeapTable.ValueConfig<PathElement> value = new HeapTable.ValueConfig<PathElement>() {
public String getDescription() {
- return "Object";
+ return "Path Element";
}
- public DocString render(Instance element) {
+ public DocString render(PathElement element) {
if (element == null) {
return DocString.link(DocString.uri("rooted"), DocString.text("ROOT"));
} else {
- return DocString.text("→ ").append(Value.render(mSnapshot, element));
+ DocString label = DocString.text(" → ");
+ label.append(Value.render(mSnapshot, element.instance));
+ label.append(element.field);
+ return label;
}
}
};
diff --git a/tools/ahat/test-dump/Main.java b/tools/ahat/test-dump/Main.java
index 3936f29..e08df67 100644
--- a/tools/ahat/test-dump/Main.java
+++ b/tools/ahat/test-dump/Main.java
@@ -29,6 +29,16 @@
// collected before we take the heap dump.
public static DumpedStuff stuff;
+ public static class ObjectTree {
+ public ObjectTree left;
+ public ObjectTree right;
+
+ public ObjectTree(ObjectTree left, ObjectTree right) {
+ this.left = left;
+ this.right = right;
+ }
+ }
+
// We will take a heap dump that includes a single instance of this
// DumpedStuff class. Objects stored as fields in this class can be easily
// found in the hprof dump by searching for the instance of the DumpedStuff
@@ -42,6 +52,11 @@
public PhantomReference aPhantomReference = new PhantomReference(anObject, referenceQueue);
public WeakReference aWeakReference = new WeakReference(anObject, referenceQueue);
public byte[] bigArray;
+ public ObjectTree[] gcPathArray = new ObjectTree[]{null, null,
+ new ObjectTree(
+ new ObjectTree(null, new ObjectTree(null, null)),
+ new ObjectTree(null, null)),
+ null};
DumpedStuff() {
int N = 1000000;
@@ -53,6 +68,8 @@
NativeAllocationRegistry registry = new NativeAllocationRegistry(
Main.class.getClassLoader(), 0x12345, 42);
registry.registerNativeAllocation(anObject, 0xABCDABCD);
+
+ gcPathArray[2].right.left = gcPathArray[2].left.right;
}
}
diff --git a/tools/ahat/test/InstanceUtilsTest.java b/tools/ahat/test/InstanceUtilsTest.java
index 59b1c90..ec77e70 100644
--- a/tools/ahat/test/InstanceUtilsTest.java
+++ b/tools/ahat/test/InstanceUtilsTest.java
@@ -16,11 +16,16 @@
package com.android.ahat;
+import com.android.tools.perflib.heap.ArrayInstance;
+import com.android.tools.perflib.heap.ClassObj;
import com.android.tools.perflib.heap.Instance;
import java.io.IOException;
+import java.util.List;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class InstanceUtilsTest {
@@ -123,4 +128,55 @@
assertEquals(referent, InstanceUtils.getReferent(wref));
assertNull(InstanceUtils.getReferent(referent));
}
+
+ @Test
+ public void gcRootPath() throws IOException {
+ TestDump dump = TestDump.getTestDump();
+
+ ClassObj main = dump.getAhatSnapshot().findClass("Main");
+ ArrayInstance gcPathArray = (ArrayInstance)dump.getDumpedThing("gcPathArray");
+ Object[] values = gcPathArray.getValues();
+ Instance base = (Instance)values[2];
+ Instance left = InstanceUtils.getRefField(base, "left");
+ Instance right = InstanceUtils.getRefField(base, "right");
+ Instance target = InstanceUtils.getRefField(left, "right");
+
+ List<InstanceUtils.PathElement> path = InstanceUtils.getPathFromGcRoot(target);
+ assertEquals(6, path.size());
+
+ assertEquals(main, path.get(0).instance);
+ assertEquals(".stuff", path.get(0).field);
+ assertTrue(path.get(0).isDominator);
+
+ assertEquals(".gcPathArray", path.get(1).field);
+ assertTrue(path.get(1).isDominator);
+
+ assertEquals(gcPathArray, path.get(2).instance);
+ assertEquals("[2]", path.get(2).field);
+ assertTrue(path.get(2).isDominator);
+
+ assertEquals(base, path.get(3).instance);
+ assertTrue(path.get(3).isDominator);
+
+ // There are two possible paths. Either it can go through the 'left' node,
+ // or the 'right' node.
+ if (path.get(3).field.equals(".left")) {
+ assertEquals(".left", path.get(3).field);
+
+ assertEquals(left, path.get(4).instance);
+ assertEquals(".right", path.get(4).field);
+ assertFalse(path.get(4).isDominator);
+
+ } else {
+ assertEquals(".right", path.get(3).field);
+
+ assertEquals(right, path.get(4).instance);
+ assertEquals(".left", path.get(4).field);
+ assertFalse(path.get(4).isDominator);
+ }
+
+ assertEquals(target, path.get(5).instance);
+ assertEquals("", path.get(5).field);
+ assertTrue(path.get(5).isDominator);
+ }
}
diff --git a/tools/jfuzz/README.md b/tools/jfuzz/README.md
index 3eb41cf..c107db1 100644
--- a/tools/jfuzz/README.md
+++ b/tools/jfuzz/README.md
@@ -62,6 +62,18 @@
--report_script : path to script called for each divergence
--jfuzz_arg : argument for jfuzz
+How to start JFuzz nightly testing
+==================================
+
+ run_jfuzz_test_nightly.py
+ [--num_proc NUM_PROC]
+
+where
+
+ --num_proc : number of run_jfuzz_test.py instances to run (8 by default)
+
+Remaining arguments are passed to run\_jfuzz_test.py.
+
How to start J/DexFuzz testing (multi-layered)
==============================================
diff --git a/tools/jfuzz/run_jfuzz_test_nightly.py b/tools/jfuzz/run_jfuzz_test_nightly.py
new file mode 100755
index 0000000..cd338fb
--- /dev/null
+++ b/tools/jfuzz/run_jfuzz_test_nightly.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3.4
+#
+# Copyright (C) 2016 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.
+
+import argparse
+import os
+import subprocess
+import sys
+
+from tempfile import TemporaryFile
+
+# Default arguments for run_jfuzz_test.py.
+DEFAULT_ARGS = ['--num_tests=20000']
+
+# run_jfuzz_test.py success string.
+SUCCESS_STRING = 'success (no divergences)'
+
+# Constant returned by string find() method when search fails.
+NOT_FOUND = -1
+
+def main(argv):
+ cwd = os.path.dirname(os.path.realpath(__file__))
+ cmd = [cwd + '/run_jfuzz_test.py'] + DEFAULT_ARGS
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--num_proc', default=8,
+ type=int, help='number of processes to run')
+ # Unknown arguments are passed to run_jfuzz_test.py.
+ (args, unknown_args) = parser.parse_known_args()
+ output_files = [TemporaryFile('wb+') for _ in range(args.num_proc)]
+ processes = []
+ for output_file in output_files:
+ processes.append(subprocess.Popen(cmd + unknown_args, stdout=output_file,
+ stderr=subprocess.STDOUT))
+ try:
+ # Wait for processes to terminate.
+ for proc in processes:
+ proc.wait()
+ except KeyboardInterrupt:
+ for proc in processes:
+ proc.kill()
+ # Output results.
+ for i, output_file in enumerate(output_files):
+ output_file.seek(0)
+ output_str = output_file.read().decode('ascii')
+ output_file.close()
+ print('Tester', i)
+ if output_str.find(SUCCESS_STRING) == NOT_FOUND:
+ print(output_str)
+ else:
+ print(SUCCESS_STRING)
+
+if __name__ == '__main__':
+ main(sys.argv)