diff options
Diffstat (limited to 'runtime')
| -rw-r--r-- | runtime/arch/context-inl.h | 55 | ||||
| -rw-r--r-- | runtime/arch/context.cc | 35 | ||||
| -rw-r--r-- | runtime/debugger.cc | 17 | ||||
| -rw-r--r-- | runtime/debugger.h | 3 | ||||
| -rw-r--r-- | runtime/dex_file_annotations.cc | 34 | ||||
| -rw-r--r-- | runtime/dex_file_annotations.h | 2 | ||||
| -rw-r--r-- | runtime/hprof/hprof.cc | 123 | ||||
| -rw-r--r-- | runtime/jdwp/jdwp_handler.cc | 15 | ||||
| -rw-r--r-- | runtime/thread.cc | 6 |
9 files changed, 212 insertions, 78 deletions
diff --git a/runtime/arch/context-inl.h b/runtime/arch/context-inl.h new file mode 100644 index 0000000000..ddcbbb18e5 --- /dev/null +++ b/runtime/arch/context-inl.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2017 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. + */ + +// This file is special-purpose for cases where you want a stack context. Most users should use +// Context::Create(). + +#include "context.h" + +#ifndef ART_RUNTIME_ARCH_CONTEXT_INL_H_ +#define ART_RUNTIME_ARCH_CONTEXT_INL_H_ + +#if defined(__arm__) +#include "arm/context_arm.h" +#define RUNTIME_CONTEXT_TYPE arm::ArmContext +#elif defined(__aarch64__) +#include "arm64/context_arm64.h" +#define RUNTIME_CONTEXT_TYPE arm64::Arm64Context +#elif defined(__mips__) && !defined(__LP64__) +#include "mips/context_mips.h" +#define RUNTIME_CONTEXT_TYPE mips::MipsContext +#elif defined(__mips__) && defined(__LP64__) +#include "mips64/context_mips64.h" +#define RUNTIME_CONTEXT_TYPE mips64::Mips64Context +#elif defined(__i386__) +#include "x86/context_x86.h" +#define RUNTIME_CONTEXT_TYPE x86::X86Context +#elif defined(__x86_64__) +#include "x86_64/context_x86_64.h" +#define RUNTIME_CONTEXT_TYPE x86_64::X86_64Context +#else +#error unimplemented +#endif + +namespace art { + +using RuntimeContextType = RUNTIME_CONTEXT_TYPE; + +} // namespace art + +#undef RUNTIME_CONTEXT_TYPE + +#endif // ART_RUNTIME_ARCH_CONTEXT_INL_H_ diff --git a/runtime/arch/context.cc b/runtime/arch/context.cc index bf40a3f8ce..82d8b6ca00 100644 --- a/runtime/arch/context.cc +++ b/runtime/arch/context.cc @@ -14,43 +14,12 @@ * limitations under the License. */ -#include "context.h" - -#if defined(__arm__) -#include "arm/context_arm.h" -#elif defined(__aarch64__) -#include "arm64/context_arm64.h" -#elif defined(__mips__) && !defined(__LP64__) -#include "mips/context_mips.h" -#elif defined(__mips__) && defined(__LP64__) -#include "mips64/context_mips64.h" -#elif defined(__i386__) -#include "x86/context_x86.h" -#elif defined(__x86_64__) -#include "x86_64/context_x86_64.h" -#else -#include "base/logging.h" -#endif +#include "context-inl.h" namespace art { Context* Context::Create() { -#if defined(__arm__) - return new arm::ArmContext(); -#elif defined(__aarch64__) - return new arm64::Arm64Context(); -#elif defined(__mips__) && !defined(__LP64__) - return new mips::MipsContext(); -#elif defined(__mips__) && defined(__LP64__) - return new mips64::Mips64Context(); -#elif defined(__i386__) - return new x86::X86Context(); -#elif defined(__x86_64__) - return new x86_64::X86_64Context(); -#else - UNIMPLEMENTED(FATAL); - return nullptr; -#endif + return new RuntimeContextType; } } // namespace art diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 63794bff6f..d0b50fe820 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1092,6 +1092,23 @@ JDWP::JdwpError Dbg::GetSignature(JDWP::RefTypeId class_id, std::string* signatu return JDWP::ERR_NONE; } +JDWP::JdwpError Dbg::GetSourceDebugExtension(JDWP::RefTypeId class_id, + std::string* extension_data) { + JDWP::JdwpError error; + mirror::Class* c = DecodeClass(class_id, &error); + if (c == nullptr) { + return error; + } + StackHandleScope<1> hs(Thread::Current()); + Handle<mirror::Class> klass(hs.NewHandle(c)); + const char* data = annotations::GetSourceDebugExtension(klass); + if (data == nullptr) { + return JDWP::ERR_ABSENT_INFORMATION; + } + *extension_data = data; + return JDWP::ERR_NONE; +} + JDWP::JdwpError Dbg::GetSourceFile(JDWP::RefTypeId class_id, std::string* result) { JDWP::JdwpError error; mirror::Class* c = DecodeClass(class_id, &error); diff --git a/runtime/debugger.h b/runtime/debugger.h index 27124e19fb..4f3ff40e86 100644 --- a/runtime/debugger.h +++ b/runtime/debugger.h @@ -288,6 +288,9 @@ class Dbg { REQUIRES_SHARED(Locks::mutator_lock_); static JDWP::JdwpError GetSignature(JDWP::RefTypeId ref_type_id, std::string* signature) REQUIRES_SHARED(Locks::mutator_lock_); + static JDWP::JdwpError GetSourceDebugExtension(JDWP::RefTypeId ref_type_id, + std::string* extension_data) + REQUIRES_SHARED(Locks::mutator_lock_); static JDWP::JdwpError GetSourceFile(JDWP::RefTypeId ref_type_id, std::string* source_file) REQUIRES_SHARED(Locks::mutator_lock_); static JDWP::JdwpError GetObjectTag(JDWP::ObjectId object_id, uint8_t* tag) diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc index 6b9654dc49..7d56bca6ce 100644 --- a/runtime/dex_file_annotations.cc +++ b/runtime/dex_file_annotations.cc @@ -1420,6 +1420,40 @@ mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirro return GetSignatureValue(data, annotation_set); } +const char* GetSourceDebugExtension(Handle<mirror::Class> klass) { + ClassData data(klass); + const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); + if (annotation_set == nullptr) { + return nullptr; + } + const DexFile::AnnotationItem* annotation_item = SearchAnnotationSet( + data.GetDexFile(), + annotation_set, + "Ldalvik/annotation/SourceDebugExtension;", + DexFile::kDexVisibilitySystem); + if (annotation_item == nullptr) { + return nullptr; + } + const uint8_t* annotation = + SearchEncodedAnnotation(data.GetDexFile(), annotation_item->annotation_, "value"); + if (annotation == nullptr) { + return nullptr; + } + DexFile::AnnotationValue annotation_value; + if (!ProcessAnnotationValue<false>(data, + &annotation, + &annotation_value, + ScopedNullHandle<mirror::Class>(), + DexFile::kAllRaw)) { + return nullptr; + } + if (annotation_value.type_ != DexFile::kDexAnnotationString) { + return nullptr; + } + dex::StringIndex index(static_cast<uint32_t>(annotation_value.value_.GetI())); + return data.GetDexFile().StringDataByIdx(index); +} + bool IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class) { ClassData data(klass); const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(data); diff --git a/runtime/dex_file_annotations.h b/runtime/dex_file_annotations.h index c66c5bdb8b..651c9844eb 100644 --- a/runtime/dex_file_annotations.h +++ b/runtime/dex_file_annotations.h @@ -89,6 +89,8 @@ bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) REQUIRES_SHARED(Locks::mutator_lock_); mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); +const char* GetSourceDebugExtension(Handle<mirror::Class> klass) + REQUIRES_SHARED(Locks::mutator_lock_); bool IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index 4f390fd30a..8bdf6b1f50 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -34,7 +34,6 @@ #include <time.h> #include <time.h> #include <unistd.h> - #include <set> #include "android-base/stringprintf.h" @@ -502,9 +501,16 @@ class Hprof : public SingleRootVisitor { void DumpHeapArray(mirror::Array* obj, mirror::Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); - void DumpHeapInstanceObject(mirror::Object* obj, mirror::Class* klass) + void DumpFakeObjectArray(mirror::Object* obj, const std::set<mirror::Object*>& elements) + REQUIRES_SHARED(Locks::mutator_lock_); + + void DumpHeapInstanceObject(mirror::Object* obj, + mirror::Class* klass, + const std::set<mirror::Object*>& fake_roots) REQUIRES_SHARED(Locks::mutator_lock_); + bool AddRuntimeInternalObjectsField(mirror::Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); + void ProcessHeap(bool header_first) REQUIRES(Locks::mutator_lock_) { // Reset current heap and object count. @@ -1062,37 +1068,17 @@ void Hprof::MarkRootObject(const mirror::Object* obj, jobject jni_obj, HprofHeap ++objects_in_segment_; } -// Use for visiting the GcRoots held live by ArtFields, ArtMethods, and ClassLoaders. -class GcRootVisitor { - public: - explicit GcRootVisitor(Hprof* hprof) : hprof_(hprof) {} - - void operator()(mirror::Object* obj ATTRIBUTE_UNUSED, - MemberOffset offset ATTRIBUTE_UNUSED, - bool is_static ATTRIBUTE_UNUSED) const {} - - // Note that these don't have read barriers. Its OK however since the GC is guaranteed to not be - // running during the hprof dumping process. - void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const - REQUIRES_SHARED(Locks::mutator_lock_) { - if (!root->IsNull()) { - VisitRoot(root); - } +bool Hprof::AddRuntimeInternalObjectsField(mirror::Class* klass) { + if (klass->IsDexCacheClass()) { + return true; } - - void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const - REQUIRES_SHARED(Locks::mutator_lock_) { - mirror::Object* obj = root->AsMirrorPtr(); - // The two cases are either classes or dex cache arrays. If it is a dex cache array, then use - // VM internal. Otherwise the object is a declaring class of an ArtField or ArtMethod or a - // class from a ClassLoader. - hprof_->VisitRoot(obj, RootInfo(obj->IsClass() ? kRootStickyClass : kRootVMInternal)); + // IsClassLoaderClass is true for subclasses of classloader but we only want to add the fake + // field to the java.lang.ClassLoader class. + if (klass->IsClassLoaderClass() && klass->GetSuperClass()->IsObjectClass()) { + return true; } - - - private: - Hprof* const hprof_; -}; + return false; +} void Hprof::DumpHeapObject(mirror::Object* obj) { // Ignore classes that are retired. @@ -1103,8 +1089,41 @@ void Hprof::DumpHeapObject(mirror::Object* obj) { ++total_objects_; - GcRootVisitor visitor(this); - obj->VisitReferences(visitor, VoidFunctor()); + class RootCollector { + public: + explicit RootCollector() {} + + void operator()(mirror::Object*, MemberOffset, bool) const {} + + // Note that these don't have read barriers. Its OK however since the GC is guaranteed to not be + // running during the hprof dumping process. + void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const + REQUIRES_SHARED(Locks::mutator_lock_) { + if (!root->IsNull()) { + VisitRoot(root); + } + } + + void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const + REQUIRES_SHARED(Locks::mutator_lock_) { + roots_.insert(root->AsMirrorPtr()); + } + + const std::set<mirror::Object*>& GetRoots() const { + return roots_; + } + + private: + // These roots are actually live from the object. Avoid marking them as roots in hprof to make + // it easier to debug class unloading. + mutable std::set<mirror::Object*> roots_; + }; + + RootCollector visitor; + // Collect all native roots. + if (!obj->IsClass()) { + obj->VisitReferences(visitor, VoidFunctor()); + } gc::Heap* const heap = Runtime::Current()->GetHeap(); const gc::space::ContinuousSpace* const space = heap->FindContinuousSpaceFromObject(obj, true); @@ -1112,15 +1131,18 @@ void Hprof::DumpHeapObject(mirror::Object* obj) { if (space != nullptr) { if (space->IsZygoteSpace()) { heap_type = HPROF_HEAP_ZYGOTE; + VisitRoot(obj, RootInfo(kRootVMInternal)); } else if (space->IsImageSpace() && heap->ObjectIsInBootImageSpace(obj)) { // Only count objects in the boot image as HPROF_HEAP_IMAGE, this leaves app image objects as // HPROF_HEAP_APP. b/35762934 heap_type = HPROF_HEAP_IMAGE; + VisitRoot(obj, RootInfo(kRootVMInternal)); } } else { const auto* los = heap->GetLargeObjectsSpace(); if (los->Contains(obj) && los->IsZygoteLargeObject(Thread::Current(), obj)) { heap_type = HPROF_HEAP_ZYGOTE; + VisitRoot(obj, RootInfo(kRootVMInternal)); } } CheckHeapSegmentConstraints(); @@ -1164,7 +1186,7 @@ void Hprof::DumpHeapObject(mirror::Object* obj) { } else if (c->IsArrayClass()) { DumpHeapArray(obj->AsArray(), c); } else { - DumpHeapInstanceObject(obj, c); + DumpHeapInstanceObject(obj, c, visitor.GetRoots()); } } @@ -1269,7 +1291,10 @@ void Hprof::DumpHeapClass(mirror::Class* klass) { // Instance fields for this class (no superclass fields) int iFieldCount = klass->NumInstanceFields(); - if (klass->IsStringClass()) { + // add_internal_runtime_objects is only for classes that may retain objects live through means + // other than fields. It is never the case for strings. + const bool add_internal_runtime_objects = AddRuntimeInternalObjectsField(klass); + if (klass->IsStringClass() || add_internal_runtime_objects) { __ AddU2((uint16_t)iFieldCount + 1); } else { __ AddU2((uint16_t)iFieldCount); @@ -1284,6 +1309,21 @@ void Hprof::DumpHeapClass(mirror::Class* klass) { if (klass->IsStringClass()) { __ AddStringId(LookupStringId("value")); __ AddU1(hprof_basic_object); + } else if (add_internal_runtime_objects) { + __ AddStringId(LookupStringId("runtimeInternalObjects")); + __ AddU1(hprof_basic_object); + } +} + +void Hprof::DumpFakeObjectArray(mirror::Object* obj, const std::set<mirror::Object*>& elements) { + __ AddU1(HPROF_OBJECT_ARRAY_DUMP); + __ AddObjectId(obj); + __ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(obj)); + __ AddU4(elements.size()); + __ AddClassId(LookupClassId( + Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kObjectArrayClass))); + for (mirror::Object* e : elements) { + __ AddObjectId(e); } } @@ -1327,7 +1367,9 @@ void Hprof::DumpHeapArray(mirror::Array* obj, mirror::Class* klass) { } } -void Hprof::DumpHeapInstanceObject(mirror::Object* obj, mirror::Class* klass) { +void Hprof::DumpHeapInstanceObject(mirror::Object* obj, + mirror::Class* klass, + const std::set<mirror::Object*>& fake_roots) { // obj is an instance object. __ AddU1(HPROF_INSTANCE_DUMP); __ AddObjectId(obj); @@ -1341,6 +1383,7 @@ void Hprof::DumpHeapInstanceObject(mirror::Object* obj, mirror::Class* klass) { // What we will use for the string value if the object is a string. mirror::Object* string_value = nullptr; + mirror::Object* fake_object_array = nullptr; // Write the instance data; fields for this class, followed by super class fields, and so on. do { @@ -1396,8 +1439,12 @@ void Hprof::DumpHeapInstanceObject(mirror::Object* obj, mirror::Class* klass) { } } __ AddObjectId(string_value); + } else if (AddRuntimeInternalObjectsField(klass)) { + // We need an id that is guaranteed to not be used, use 1/2 of the object alignment. + fake_object_array = reinterpret_cast<mirror::Object*>( + reinterpret_cast<uintptr_t>(obj) + kObjectAlignment / 2); + __ AddObjectId(fake_object_array); } - klass = klass->GetSuperClass(); } while (klass != nullptr); @@ -1419,6 +1466,8 @@ void Hprof::DumpHeapInstanceObject(mirror::Object* obj, mirror::Class* klass) { __ AddU1(hprof_basic_char); __ AddU2List(s->GetValue(), s->GetLength()); } + } else if (fake_object_array != nullptr) { + DumpFakeObjectArray(fake_object_array, fake_roots); } } diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc index 971d03958c..e8a9904dc6 100644 --- a/runtime/jdwp/jdwp_handler.cc +++ b/runtime/jdwp/jdwp_handler.cc @@ -335,7 +335,7 @@ static JdwpError VM_CapabilitiesNew(JdwpState*, Request* request, ExpandBuf* rep expandBufAdd1(reply, false); // canUnrestrictedlyRedefineClasses expandBufAdd1(reply, false); // canPopFrames expandBufAdd1(reply, true); // canUseInstanceFilters - expandBufAdd1(reply, false); // canGetSourceDebugExtension + expandBufAdd1(reply, true); // canGetSourceDebugExtension expandBufAdd1(reply, false); // canRequestVMDeathEvent expandBufAdd1(reply, false); // canSetDefaultStratum expandBufAdd1(reply, true); // 1.6: canGetInstanceInfo @@ -499,13 +499,18 @@ static JdwpError RT_ClassObject(JdwpState*, Request* request, ExpandBuf* pReply) /* * Returns the value of the SourceDebugExtension attribute. - * - * JDB seems interested, but DEX files don't currently support this. */ -static JdwpError RT_SourceDebugExtension(JdwpState*, Request*, ExpandBuf*) +static JdwpError RT_SourceDebugExtension(JdwpState*, Request* request, ExpandBuf* pReply) REQUIRES_SHARED(Locks::mutator_lock_) { /* referenceTypeId in, string out */ - return ERR_ABSENT_INFORMATION; + RefTypeId refTypeId = request->ReadRefTypeId(); + std::string extension_data; + JdwpError status = Dbg::GetSourceDebugExtension(refTypeId, &extension_data); + if (status != ERR_NONE) { + return status; + } + expandBufAddUtf8String(pReply, extension_data); + return ERR_NONE; } static JdwpError RT_Signature(JdwpState*, Request* request, ExpandBuf* pReply, bool with_generic) diff --git a/runtime/thread.cc b/runtime/thread.cc index 201701a510..62a616b646 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -35,6 +35,7 @@ #include "android-base/stringprintf.h" #include "arch/context.h" +#include "arch/context-inl.h" #include "art_field-inl.h" #include "art_method-inl.h" #include "base/bit_utils.h" @@ -3413,11 +3414,10 @@ void Thread::VisitRoots(RootVisitor* visitor) { verifier->VisitRoots(visitor, RootInfo(kRootNativeStack, thread_id)); } // Visit roots on this thread's stack - Context* context = GetLongJumpContext(); + RuntimeContextType context; RootCallbackVisitor visitor_to_callback(visitor, thread_id); - ReferenceMapVisitor<RootCallbackVisitor, kPrecise> mapper(this, context, visitor_to_callback); + ReferenceMapVisitor<RootCallbackVisitor, kPrecise> mapper(this, &context, visitor_to_callback); mapper.template WalkStack<StackVisitor::CountTransitions::kNo>(false); - ReleaseLongJumpContext(context); for (instrumentation::InstrumentationStackFrame& frame : *GetInstrumentationStack()) { visitor->VisitRootIfNonNull(&frame.this_object_, RootInfo(kRootVMInternal, thread_id)); } |