summaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/arch/context-inl.h55
-rw-r--r--runtime/arch/context.cc35
-rw-r--r--runtime/debugger.cc17
-rw-r--r--runtime/debugger.h3
-rw-r--r--runtime/dex_file_annotations.cc34
-rw-r--r--runtime/dex_file_annotations.h2
-rw-r--r--runtime/hprof/hprof.cc123
-rw-r--r--runtime/jdwp/jdwp_handler.cc15
-rw-r--r--runtime/thread.cc6
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));
}