Merge "Mterp: Add missing shadow reg clear to op_long_to_double"
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index 48da755..1725154 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -24,11 +24,11 @@
#include "detail/cmdline_debug_detail.h"
#include "memory_representation.h"
+#include "android-base/logging.h"
#include "android-base/strings.h"
// Includes for the types that are being specialized
#include <string>
-#include "base/logging.h"
#include "base/time_utils.h"
#include "experimental_flags.h"
#include "gc/collector_type.h"
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 45d9167..ec93222 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -18,6 +18,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
+#include "base/logging.h"
#include "builder.h"
#include "class_linker.h"
#include "class_root.h"
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index e9b5b5a..448fed9 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -19,6 +19,7 @@
#include "art_method-inl.h"
#include "base/arena_bit_vector.h"
#include "base/bit_vector-inl.h"
+#include "base/logging.h"
#include "block_builder.h"
#include "class_linker-inl.h"
#include "code_generator.h"
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index aad06b9..3f225f3 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -20,6 +20,7 @@
#include "art_method-inl.h"
#include "base/bit_utils.h"
#include "base/bit_vector-inl.h"
+#include "base/logging.h"
#include "base/stl_util.h"
#include "class_linker-inl.h"
#include "class_root.h"
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 1db20fc..1d3fcf3 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -26,6 +26,7 @@
#include "base/arena_allocator.h"
#include "base/arena_containers.h"
#include "base/dumpable.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "base/scoped_arena_allocator.h"
diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h
index 1f4f6d5..ddd57f5 100644
--- a/compiler/optimizing/optimizing_compiler_stats.h
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -22,9 +22,10 @@
#include <string>
#include <type_traits>
+#include <android-base/logging.h>
+
#include "base/atomic.h"
#include "base/globals.h"
-#include "base/logging.h" // For VLOG_IS_ON.
namespace art {
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 16c23c8..cef234a 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -18,6 +18,7 @@
#include "base/arena_bit_vector.h"
#include "base/bit_vector-inl.h"
+#include "base/logging.h"
#include "data_type-inl.h"
#include "dex/bytecode_utils.h"
#include "mirror/class-inl.h"
diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h
index e9c1a82..adfc864 100644
--- a/libdexfile/dex/class_accessor.h
+++ b/libdexfile/dex/class_accessor.h
@@ -264,7 +264,7 @@
};
// Not explicit specifically for range-based loops.
- ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data);
+ ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data); // NOLINT [runtime/explicit] [5]
ALWAYS_INLINE ClassAccessor(const DexFile& dex_file,
const DexFile::ClassDef& class_def,
diff --git a/libdexfile/dex/class_iterator.h b/libdexfile/dex/class_iterator.h
index 477c93b..8ed585b 100644
--- a/libdexfile/dex/class_iterator.h
+++ b/libdexfile/dex/class_iterator.h
@@ -17,7 +17,7 @@
#ifndef ART_LIBDEXFILE_DEX_CLASS_ITERATOR_H_
#define ART_LIBDEXFILE_DEX_CLASS_ITERATOR_H_
-#include "base/logging.h"
+#include <android-base/logging.h>
namespace art {
diff --git a/libdexfile/dex/type_lookup_table.h b/libdexfile/dex/type_lookup_table.h
index 7005d34..5f002d1 100644
--- a/libdexfile/dex/type_lookup_table.h
+++ b/libdexfile/dex/type_lookup_table.h
@@ -17,7 +17,8 @@
#ifndef ART_LIBDEXFILE_DEX_TYPE_LOOKUP_TABLE_H_
#define ART_LIBDEXFILE_DEX_TYPE_LOOKUP_TABLE_H_
-#include "base/logging.h"
+#include <android-base/logging.h>
+
#include "dex/dex_file_types.h"
namespace art {
diff --git a/openjdkjvmti/ti_class_definition.cc b/openjdkjvmti/ti_class_definition.cc
index 2a56512..795a68a 100644
--- a/openjdkjvmti/ti_class_definition.cc
+++ b/openjdkjvmti/ti_class_definition.cc
@@ -32,6 +32,7 @@
#include "ti_class_definition.h"
#include "base/array_slice.h"
+#include "base/logging.h"
#include "class_linker-inl.h"
#include "class_root.h"
#include "dex/dex_file.h"
diff --git a/openjdkjvmti/ti_logging.h b/openjdkjvmti/ti_logging.h
index 31b51bb..a1be090 100644
--- a/openjdkjvmti/ti_logging.h
+++ b/openjdkjvmti/ti_logging.h
@@ -37,8 +37,9 @@
#include <ostream>
#include <sstream>
-#include "base/logging.h"
-#include "base/macros.h"
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+
#include "base/mutex.h"
#include "thread-current-inl.h"
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index 5de4a81..4a3eac8 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -673,34 +673,24 @@
return ERR(NONE);
}
-// Walks up the stack counting Java frames. This is not StackVisitor::ComputeNumFrames, as
-// runtime methods and transitions must not be counted.
-struct GetFrameCountVisitor : public art::StackVisitor {
- explicit GetFrameCountVisitor(art::Thread* thread)
- : art::StackVisitor(thread, nullptr, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- count(0) {}
-
- bool VisitFrame() override REQUIRES_SHARED(art::Locks::mutator_lock_) {
- art::ArtMethod* m = GetMethod();
- const bool do_count = !(m == nullptr || m->IsRuntimeMethod());
- if (do_count) {
- count++;
- }
- return true;
- }
-
- size_t count;
-};
-
struct GetFrameCountClosure : public art::Closure {
public:
GetFrameCountClosure() : count(0) {}
void Run(art::Thread* self) override REQUIRES_SHARED(art::Locks::mutator_lock_) {
- GetFrameCountVisitor visitor(self);
- visitor.WalkStack(false);
-
- count = visitor.count;
+ // This is not StackVisitor::ComputeNumFrames, as runtime methods and transitions must not be
+ // counted.
+ art::StackVisitor::WalkStack(
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ art::ArtMethod* m = stack_visitor->GetMethod();
+ if (m != nullptr && !m->IsRuntimeMethod()) {
+ count++;
+ }
+ return true;
+ },
+ self,
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
}
size_t count;
@@ -743,46 +733,30 @@
return ERR(NONE);
}
-// Walks up the stack 'n' callers, when used with Thread::WalkStack.
-struct GetLocationVisitor : public art::StackVisitor {
- GetLocationVisitor(art::Thread* thread, size_t n_in)
- : art::StackVisitor(thread, nullptr, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- n(n_in),
- count(0),
- caller(nullptr),
- caller_dex_pc(0) {}
-
- bool VisitFrame() override REQUIRES_SHARED(art::Locks::mutator_lock_) {
- art::ArtMethod* m = GetMethod();
- const bool do_count = !(m == nullptr || m->IsRuntimeMethod());
- if (do_count) {
- DCHECK(caller == nullptr);
- if (count == n) {
- caller = m;
- caller_dex_pc = GetDexPc(false);
- return false;
- }
- count++;
- }
- return true;
- }
-
- const size_t n;
- size_t count;
- art::ArtMethod* caller;
- uint32_t caller_dex_pc;
-};
-
struct GetLocationClosure : public art::Closure {
public:
explicit GetLocationClosure(size_t n_in) : n(n_in), method(nullptr), dex_pc(0) {}
void Run(art::Thread* self) override REQUIRES_SHARED(art::Locks::mutator_lock_) {
- GetLocationVisitor visitor(self, n);
- visitor.WalkStack(false);
-
- method = visitor.caller;
- dex_pc = visitor.caller_dex_pc;
+ // Walks up the stack 'n' callers.
+ size_t count = 0u;
+ art::StackVisitor::WalkStack(
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ art::ArtMethod* m = stack_visitor->GetMethod();
+ if (m != nullptr && !m->IsRuntimeMethod()) {
+ DCHECK(method == nullptr);
+ if (count == n) {
+ method = m;
+ dex_pc = stack_visitor->GetDexPc(/*abort_on_failure=*/false);
+ return false;
+ }
+ count++;
+ }
+ return true;
+ },
+ self,
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
}
const size_t n;
diff --git a/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc
index 8bd10da..27f04b7 100644
--- a/openjdkjvmti/transform.cc
+++ b/openjdkjvmti/transform.cc
@@ -40,6 +40,7 @@
#include "art_method.h"
#include "base/array_ref.h"
#include "base/globals.h"
+#include "base/logging.h"
#include "base/mem_map.h"
#include "class_linker.h"
#include "dex/dex_file.h"
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 7a08cb3..0dc0723 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -436,20 +436,15 @@
ThrowException("Ljava/lang/NullPointerException;", nullptr, msg.str().c_str());
}
-void ThrowNullPointerExceptionForMethodAccess(uint32_t method_idx,
- InvokeType type) {
- ObjPtr<mirror::DexCache> dex_cache =
- Thread::Current()->GetCurrentMethod(nullptr)->GetDeclaringClass()->GetDexCache();
- const DexFile& dex_file = *dex_cache->GetDexFile();
+void ThrowNullPointerExceptionForMethodAccess(uint32_t method_idx, InvokeType type) {
+ const DexFile& dex_file = *Thread::Current()->GetCurrentMethod(nullptr)->GetDexFile();
ThrowNullPointerExceptionForMethodAccessImpl(method_idx, dex_file, type);
}
-void ThrowNullPointerExceptionForMethodAccess(ArtMethod* method,
- InvokeType type) {
- ObjPtr<mirror::DexCache> dex_cache = method->GetDeclaringClass()->GetDexCache();
- const DexFile& dex_file = *dex_cache->GetDexFile();
+void ThrowNullPointerExceptionForMethodAccess(ArtMethod* method, InvokeType type) {
ThrowNullPointerExceptionForMethodAccessImpl(method->GetDexMethodIndex(),
- dex_file, type);
+ *method->GetDexFile(),
+ type);
}
static bool IsValidReadBarrierImplicitCheck(uintptr_t addr) {
@@ -577,7 +572,7 @@
CHECK_LT(throw_dex_pc, accessor.InsnsSizeInCodeUnits());
const Instruction& instr = accessor.InstructionAt(throw_dex_pc);
if (check_address && !IsValidImplicitCheck(addr, instr)) {
- const DexFile* dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+ const DexFile* dex_file = method->GetDexFile();
LOG(FATAL) << "Invalid address for an implicit NullPointerException check: "
<< "0x" << std::hex << addr << std::dec
<< ", at "
@@ -717,8 +712,7 @@
break;
}
default: {
- const DexFile* dex_file =
- method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+ const DexFile* dex_file = method->GetDexFile();
LOG(FATAL) << "NullPointerException at an unexpected instruction: "
<< instr.DumpString(dex_file)
<< " in "
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 3ad7fc9..4af97f0 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -2362,25 +2362,18 @@
}
static int GetStackDepth(Thread* thread) REQUIRES_SHARED(Locks::mutator_lock_) {
- struct CountStackDepthVisitor : public StackVisitor {
- explicit CountStackDepthVisitor(Thread* thread_in)
- : StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- depth(0) {}
-
- // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
- // annotalysis.
- bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
- if (!GetMethod()->IsRuntimeMethod()) {
- ++depth;
- }
- return true;
- }
- size_t depth;
- };
-
- CountStackDepthVisitor visitor(thread);
- visitor.WalkStack();
- return visitor.depth;
+ size_t depth = 0u;
+ StackVisitor::WalkStack(
+ [&depth](const StackVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!visitor->GetMethod()->IsRuntimeMethod()) {
+ ++depth;
+ }
+ return true;
+ },
+ thread,
+ /* context= */ nullptr,
+ StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+ return depth;
}
JDWP::JdwpError Dbg::GetThreadFrameCount(JDWP::ObjectId thread_id, size_t* result) {
@@ -2398,47 +2391,10 @@
return JDWP::ERR_NONE;
}
-JDWP::JdwpError Dbg::GetThreadFrames(JDWP::ObjectId thread_id, size_t start_frame,
- size_t frame_count, JDWP::ExpandBuf* buf) {
- class GetFrameVisitor : public StackVisitor {
- public:
- GetFrameVisitor(Thread* thread, size_t start_frame_in, size_t frame_count_in,
- JDWP::ExpandBuf* buf_in)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- depth_(0),
- start_frame_(start_frame_in),
- frame_count_(frame_count_in),
- buf_(buf_in) {
- expandBufAdd4BE(buf_, frame_count_);
- }
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- if (GetMethod()->IsRuntimeMethod()) {
- return true; // The debugger can't do anything useful with a frame that has no Method*.
- }
- if (depth_ >= start_frame_ + frame_count_) {
- return false;
- }
- if (depth_ >= start_frame_) {
- JDWP::FrameId frame_id(GetFrameId());
- JDWP::JdwpLocation location;
- SetJdwpLocation(&location, GetMethod(), GetDexPc());
- VLOG(jdwp) << StringPrintf(" Frame %3zd: id=%3" PRIu64 " ", depth_, frame_id) << location;
- expandBufAdd8BE(buf_, frame_id);
- expandBufAddLocation(buf_, location);
- }
- ++depth_;
- return true;
- }
-
- private:
- size_t depth_;
- const size_t start_frame_;
- const size_t frame_count_;
- JDWP::ExpandBuf* buf_;
- };
-
+JDWP::JdwpError Dbg::GetThreadFrames(JDWP::ObjectId thread_id,
+ const size_t start_frame,
+ const size_t frame_count,
+ JDWP::ExpandBuf* buf) {
ScopedObjectAccessUnchecked soa(Thread::Current());
JDWP::JdwpError error;
Thread* thread = DecodeThread(soa, thread_id, &error);
@@ -2448,8 +2404,34 @@
if (!IsSuspendedForDebugger(soa, thread)) {
return JDWP::ERR_THREAD_NOT_SUSPENDED;
}
- GetFrameVisitor visitor(thread, start_frame, frame_count, buf);
- visitor.WalkStack();
+
+ expandBufAdd4BE(buf, frame_count);
+
+ size_t depth = 0u;
+ StackVisitor::WalkStack(
+ [&](StackVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (visitor->GetMethod()->IsRuntimeMethod()) {
+ return true; // The debugger can't do anything useful with a frame that has no Method*.
+ }
+ if (depth >= start_frame + frame_count) {
+ return false;
+ }
+ if (depth >= start_frame) {
+ JDWP::FrameId frame_id(visitor->GetFrameId());
+ JDWP::JdwpLocation location;
+ SetJdwpLocation(&location, visitor->GetMethod(), visitor->GetDexPc());
+ VLOG(jdwp)
+ << StringPrintf(" Frame %3zd: id=%3" PRIu64 " ", depth, frame_id) << location;
+ expandBufAdd8BE(buf, frame_id);
+ expandBufAddLocation(buf, location);
+ }
+ ++depth;
+ return true;
+ },
+ thread,
+ /* context= */ nullptr,
+ StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+
return JDWP::ERR_NONE;
}
@@ -2530,28 +2512,6 @@
Runtime::Current()->GetThreadList()->SuspendSelfForDebugger();
}
-struct GetThisVisitor : public StackVisitor {
- GetThisVisitor(Thread* thread, Context* context, JDWP::FrameId frame_id_in)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- this_object(nullptr),
- frame_id(frame_id_in) {}
-
- // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
- // annotalysis.
- bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
- if (frame_id != GetFrameId()) {
- return true; // continue
- } else {
- this_object = GetThisObject();
- return false;
- }
- }
-
- mirror::Object* this_object;
- JDWP::FrameId frame_id;
-};
-
JDWP::JdwpError Dbg::GetThisObject(JDWP::ObjectId thread_id, JDWP::FrameId frame_id,
JDWP::ObjectId* result) {
ScopedObjectAccessUnchecked soa(Thread::Current());
@@ -2564,48 +2524,50 @@
return JDWP::ERR_THREAD_NOT_SUSPENDED;
}
std::unique_ptr<Context> context(Context::Create());
- GetThisVisitor visitor(thread, context.get(), frame_id);
- visitor.WalkStack();
- *result = gRegistry->Add(visitor.this_object);
+ mirror::Object* this_object = nullptr;
+ StackVisitor::WalkStack(
+ [&](art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (frame_id != stack_visitor->GetFrameId()) {
+ return true; // continue
+ } else {
+ this_object = stack_visitor->GetThisObject();
+ return false;
+ }
+ },
+ thread,
+ context.get(),
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+ *result = gRegistry->Add(this_object);
return JDWP::ERR_NONE;
}
-// Walks the stack until we find the frame with the given FrameId.
-class FindFrameVisitor final : public StackVisitor {
- public:
- FindFrameVisitor(Thread* thread, Context* context, JDWP::FrameId frame_id)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- frame_id_(frame_id),
- error_(JDWP::ERR_INVALID_FRAMEID) {}
-
- // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
- // annotalysis.
- bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
- if (GetFrameId() != frame_id_) {
- return true; // Not our frame, carry on.
- }
- ArtMethod* m = GetMethod();
- if (m->IsNative()) {
- // We can't read/write local value from/into native method.
- error_ = JDWP::ERR_OPAQUE_FRAME;
- } else {
- // We found our frame.
- error_ = JDWP::ERR_NONE;
- }
- return false;
- }
-
- JDWP::JdwpError GetError() const {
- return error_;
- }
-
- private:
- const JDWP::FrameId frame_id_;
- JDWP::JdwpError error_;
-
- DISALLOW_COPY_AND_ASSIGN(FindFrameVisitor);
-};
+template <typename FrameHandler>
+static JDWP::JdwpError FindAndHandleNonNativeFrame(Thread* thread,
+ JDWP::FrameId frame_id,
+ const FrameHandler& handler)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ JDWP::JdwpError result = JDWP::ERR_INVALID_FRAMEID;
+ std::unique_ptr<Context> context(Context::Create());
+ StackVisitor::WalkStack(
+ [&](art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (stack_visitor->GetFrameId() != frame_id) {
+ return true; // Not our frame, carry on.
+ }
+ ArtMethod* m = stack_visitor->GetMethod();
+ if (m->IsNative()) {
+ // We can't read/write local value from/into native method.
+ result = JDWP::ERR_OPAQUE_FRAME;
+ } else {
+ // We found our frame.
+ result = handler(stack_visitor);
+ }
+ return false;
+ },
+ thread,
+ context.get(),
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+ return result;
+}
JDWP::JdwpError Dbg::GetLocalValues(JDWP::Request* request, JDWP::ExpandBuf* pReply) {
JDWP::ObjectId thread_id = request->ReadThreadId();
@@ -2620,31 +2582,29 @@
if (!IsSuspendedForDebugger(soa, thread)) {
return JDWP::ERR_THREAD_NOT_SUSPENDED;
}
- // Find the frame with the given frame_id.
- std::unique_ptr<Context> context(Context::Create());
- FindFrameVisitor visitor(thread, context.get(), frame_id);
- visitor.WalkStack();
- if (visitor.GetError() != JDWP::ERR_NONE) {
- return visitor.GetError();
- }
- // Read the values from visitor's context.
- int32_t slot_count = request->ReadSigned32("slot count");
- expandBufAdd4BE(pReply, slot_count); /* "int values" */
- for (int32_t i = 0; i < slot_count; ++i) {
- uint32_t slot = request->ReadUnsigned32("slot");
- JDWP::JdwpTag reqSigByte = request->ReadTag();
+ return FindAndHandleNonNativeFrame(
+ thread,
+ frame_id,
+ [&](art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Read the values from visitor's context.
+ int32_t slot_count = request->ReadSigned32("slot count");
+ expandBufAdd4BE(pReply, slot_count); /* "int values" */
+ for (int32_t i = 0; i < slot_count; ++i) {
+ uint32_t slot = request->ReadUnsigned32("slot");
+ JDWP::JdwpTag reqSigByte = request->ReadTag();
- VLOG(jdwp) << " --> slot " << slot << " " << reqSigByte;
+ VLOG(jdwp) << " --> slot " << slot << " " << reqSigByte;
- size_t width = Dbg::GetTagWidth(reqSigByte);
- uint8_t* ptr = expandBufAddSpace(pReply, width + 1);
- error = Dbg::GetLocalValue(visitor, soa, slot, reqSigByte, ptr, width);
- if (error != JDWP::ERR_NONE) {
- return error;
- }
- }
- return JDWP::ERR_NONE;
+ size_t width = Dbg::GetTagWidth(reqSigByte);
+ uint8_t* ptr = expandBufAddSpace(pReply, width + 1);
+ error = Dbg::GetLocalValue(*stack_visitor, soa, slot, reqSigByte, ptr, width);
+ if (error != JDWP::ERR_NONE) {
+ return error;
+ }
+ }
+ return JDWP::ERR_NONE;
+ });
}
constexpr JDWP::JdwpError kStackFrameLocalAccessError = JDWP::ERR_ABSENT_INFORMATION;
@@ -2791,29 +2751,27 @@
if (!IsSuspendedForDebugger(soa, thread)) {
return JDWP::ERR_THREAD_NOT_SUSPENDED;
}
- // Find the frame with the given frame_id.
- std::unique_ptr<Context> context(Context::Create());
- FindFrameVisitor visitor(thread, context.get(), frame_id);
- visitor.WalkStack();
- if (visitor.GetError() != JDWP::ERR_NONE) {
- return visitor.GetError();
- }
- // Writes the values into visitor's context.
- int32_t slot_count = request->ReadSigned32("slot count");
- for (int32_t i = 0; i < slot_count; ++i) {
- uint32_t slot = request->ReadUnsigned32("slot");
- JDWP::JdwpTag sigByte = request->ReadTag();
- size_t width = Dbg::GetTagWidth(sigByte);
- uint64_t value = request->ReadValue(width);
+ return FindAndHandleNonNativeFrame(
+ thread,
+ frame_id,
+ [&](art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Writes the values into visitor's context.
+ int32_t slot_count = request->ReadSigned32("slot count");
+ for (int32_t i = 0; i < slot_count; ++i) {
+ uint32_t slot = request->ReadUnsigned32("slot");
+ JDWP::JdwpTag sigByte = request->ReadTag();
+ size_t width = Dbg::GetTagWidth(sigByte);
+ uint64_t value = request->ReadValue(width);
- VLOG(jdwp) << " --> slot " << slot << " " << sigByte << " " << value;
- error = Dbg::SetLocalValue(thread, visitor, slot, sigByte, value, width);
- if (error != JDWP::ERR_NONE) {
- return error;
- }
- }
- return JDWP::ERR_NONE;
+ VLOG(jdwp) << " --> slot " << slot << " " << sigByte << " " << value;
+ error = Dbg::SetLocalValue(thread, *stack_visitor, slot, sigByte, value, width);
+ if (error != JDWP::ERR_NONE) {
+ return error;
+ }
+ }
+ return JDWP::ERR_NONE;
+ });
}
template<typename T>
@@ -2985,107 +2943,71 @@
gJdwpState->PostFieldEvent(&location, f, this_object, field_value, true);
}
-/**
- * Finds the location where this exception will be caught. We search until we reach the top
- * frame, in which case this exception is considered uncaught.
- */
-class CatchLocationFinder : public StackVisitor {
- public:
- CatchLocationFinder(Thread* self, const Handle<mirror::Throwable>& exception, Context* context)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(self, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- exception_(exception),
- handle_scope_(self),
- this_at_throw_(handle_scope_.NewHandle<mirror::Object>(nullptr)),
- catch_method_(nullptr),
- throw_method_(nullptr),
- catch_dex_pc_(dex::kDexNoIndex),
- throw_dex_pc_(dex::kDexNoIndex) {
- }
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* method = GetMethod();
- DCHECK(method != nullptr);
- if (method->IsRuntimeMethod()) {
- // Ignore callee save method.
- DCHECK(method->IsCalleeSaveMethod());
- return true;
- }
-
- uint32_t dex_pc = GetDexPc();
- if (throw_method_ == nullptr) {
- // First Java method found. It is either the method that threw the exception,
- // or the Java native method that is reporting an exception thrown by
- // native code.
- this_at_throw_.Assign(GetThisObject());
- throw_method_ = method;
- throw_dex_pc_ = dex_pc;
- }
-
- if (dex_pc != dex::kDexNoIndex) {
- StackHandleScope<1> hs(GetThread());
- uint32_t found_dex_pc;
- Handle<mirror::Class> exception_class(hs.NewHandle(exception_->GetClass()));
- bool unused_clear_exception;
- found_dex_pc = method->FindCatchBlock(exception_class, dex_pc, &unused_clear_exception);
- if (found_dex_pc != dex::kDexNoIndex) {
- catch_method_ = method;
- catch_dex_pc_ = found_dex_pc;
- return false; // End stack walk.
- }
- }
- return true; // Continue stack walk.
- }
-
- ArtMethod* GetCatchMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
- return catch_method_;
- }
-
- ArtMethod* GetThrowMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
- return throw_method_;
- }
-
- mirror::Object* GetThisAtThrow() REQUIRES_SHARED(Locks::mutator_lock_) {
- return this_at_throw_.Get();
- }
-
- uint32_t GetCatchDexPc() const {
- return catch_dex_pc_;
- }
-
- uint32_t GetThrowDexPc() const {
- return throw_dex_pc_;
- }
-
- private:
- const Handle<mirror::Throwable>& exception_;
- StackHandleScope<1> handle_scope_;
- MutableHandle<mirror::Object> this_at_throw_;
- ArtMethod* catch_method_;
- ArtMethod* throw_method_;
- uint32_t catch_dex_pc_;
- uint32_t throw_dex_pc_;
-
- DISALLOW_COPY_AND_ASSIGN(CatchLocationFinder);
-};
-
void Dbg::PostException(mirror::Throwable* exception_object) {
if (!IsDebuggerActive()) {
return;
}
Thread* const self = Thread::Current();
- StackHandleScope<1> handle_scope(self);
+ StackHandleScope<2> handle_scope(self);
Handle<mirror::Throwable> h_exception(handle_scope.NewHandle(exception_object));
+ MutableHandle<mirror::Object> this_at_throw = handle_scope.NewHandle<mirror::Object>(nullptr);
std::unique_ptr<Context> context(Context::Create());
- CatchLocationFinder clf(self, h_exception, context.get());
- clf.WalkStack(/* include_transitions= */ false);
- JDWP::EventLocation exception_throw_location;
- SetEventLocation(&exception_throw_location, clf.GetThrowMethod(), clf.GetThrowDexPc());
- JDWP::EventLocation exception_catch_location;
- SetEventLocation(&exception_catch_location, clf.GetCatchMethod(), clf.GetCatchDexPc());
- gJdwpState->PostException(&exception_throw_location, h_exception.Get(), &exception_catch_location,
- clf.GetThisAtThrow());
+ ArtMethod* catch_method = nullptr;
+ ArtMethod* throw_method = nullptr;
+ uint32_t catch_dex_pc = dex::kDexNoIndex;
+ uint32_t throw_dex_pc = dex::kDexNoIndex;
+ StackVisitor::WalkStack(
+ /**
+ * Finds the location where this exception will be caught. We search until we reach the top
+ * frame, in which case this exception is considered uncaught.
+ */
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* method = stack_visitor->GetMethod();
+ DCHECK(method != nullptr);
+ if (method->IsRuntimeMethod()) {
+ // Ignore callee save method.
+ DCHECK(method->IsCalleeSaveMethod());
+ return true;
+ }
+
+ uint32_t dex_pc = stack_visitor->GetDexPc();
+ if (throw_method == nullptr) {
+ // First Java method found. It is either the method that threw the exception,
+ // or the Java native method that is reporting an exception thrown by
+ // native code.
+ this_at_throw.Assign(stack_visitor->GetThisObject());
+ throw_method = method;
+ throw_dex_pc = dex_pc;
+ }
+
+ if (dex_pc != dex::kDexNoIndex) {
+ StackHandleScope<1> hs(stack_visitor->GetThread());
+ uint32_t found_dex_pc;
+ Handle<mirror::Class> exception_class(hs.NewHandle(h_exception->GetClass()));
+ bool unused_clear_exception;
+ found_dex_pc = method->FindCatchBlock(exception_class, dex_pc, &unused_clear_exception);
+ if (found_dex_pc != dex::kDexNoIndex) {
+ catch_method = method;
+ catch_dex_pc = found_dex_pc;
+ return false; // End stack walk.
+ }
+ }
+ return true; // Continue stack walk.
+ },
+ self,
+ context.get(),
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+
+ JDWP::EventLocation exception_throw_location;
+ SetEventLocation(&exception_throw_location, throw_method, throw_dex_pc);
+ JDWP::EventLocation exception_catch_location;
+ SetEventLocation(&exception_catch_location, catch_method, catch_dex_pc);
+
+ gJdwpState->PostException(&exception_throw_location,
+ h_exception.Get(),
+ &exception_catch_location,
+ this_at_throw.Get());
}
void Dbg::PostClassPrepare(mirror::Class* c) {
@@ -3649,56 +3571,6 @@
return instrumentation->IsDeoptimized(m);
}
-class NeedsDeoptimizationVisitor : public StackVisitor {
- public:
- explicit NeedsDeoptimizationVisitor(Thread* self)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(self, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- needs_deoptimization_(false) {}
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- // The visitor is meant to be used when handling exception from compiled code only.
- CHECK(!IsShadowFrame()) << "We only expect to visit compiled frame: "
- << ArtMethod::PrettyMethod(GetMethod());
- ArtMethod* method = GetMethod();
- if (method == nullptr) {
- // We reach an upcall and don't need to deoptimize this part of the stack (ManagedFragment)
- // so we can stop the visit.
- DCHECK(!needs_deoptimization_);
- return false;
- }
- if (Runtime::Current()->GetInstrumentation()->InterpretOnly()) {
- // We found a compiled frame in the stack but instrumentation is set to interpret
- // everything: we need to deoptimize.
- needs_deoptimization_ = true;
- return false;
- }
- if (Runtime::Current()->GetInstrumentation()->IsDeoptimized(method)) {
- // We found a deoptimized method in the stack.
- needs_deoptimization_ = true;
- return false;
- }
- ShadowFrame* frame = GetThread()->FindDebuggerShadowFrame(GetFrameId());
- if (frame != nullptr) {
- // The debugger allocated a ShadowFrame to update a variable in the stack: we need to
- // deoptimize the stack to execute (and deallocate) this frame.
- needs_deoptimization_ = true;
- return false;
- }
- return true;
- }
-
- bool NeedsDeoptimization() const {
- return needs_deoptimization_;
- }
-
- private:
- // Do we need to deoptimize the stack?
- bool needs_deoptimization_;
-
- DISALLOW_COPY_AND_ASSIGN(NeedsDeoptimizationVisitor);
-};
-
// Do we need to deoptimize the stack to handle an exception?
bool Dbg::IsForcedInterpreterNeededForExceptionImpl(Thread* thread) {
const SingleStepControl* const ssc = thread->GetSingleStepControl();
@@ -3708,9 +3580,45 @@
}
// Deoptimization is required if at least one method in the stack needs it. However we
// skip frames that will be unwound (thus not executed).
- NeedsDeoptimizationVisitor visitor(thread);
- visitor.WalkStack(true); // includes upcall.
- return visitor.NeedsDeoptimization();
+ bool needs_deoptimization = false;
+ StackVisitor::WalkStack(
+ [&](art::StackVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ // The visitor is meant to be used when handling exception from compiled code only.
+ CHECK(!visitor->IsShadowFrame()) << "We only expect to visit compiled frame: "
+ << ArtMethod::PrettyMethod(visitor->GetMethod());
+ ArtMethod* method = visitor->GetMethod();
+ if (method == nullptr) {
+ // We reach an upcall and don't need to deoptimize this part of the stack (ManagedFragment)
+ // so we can stop the visit.
+ DCHECK(!needs_deoptimization);
+ return false;
+ }
+ if (Runtime::Current()->GetInstrumentation()->InterpretOnly()) {
+ // We found a compiled frame in the stack but instrumentation is set to interpret
+ // everything: we need to deoptimize.
+ needs_deoptimization = true;
+ return false;
+ }
+ if (Runtime::Current()->GetInstrumentation()->IsDeoptimized(method)) {
+ // We found a deoptimized method in the stack.
+ needs_deoptimization = true;
+ return false;
+ }
+ ShadowFrame* frame = visitor->GetThread()->FindDebuggerShadowFrame(visitor->GetFrameId());
+ if (frame != nullptr) {
+ // The debugger allocated a ShadowFrame to update a variable in the stack: we need to
+ // deoptimize the stack to execute (and deallocate) this frame.
+ needs_deoptimization = true;
+ return false;
+ }
+ return true;
+ },
+ thread,
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames,
+ /* check_suspended */ true,
+ /* include_transitions */ true);
+ return needs_deoptimization;
}
// Scoped utility class to suspend a thread so that we may do tasks such as walk its stack. Doesn't
diff --git a/runtime/dex_to_dex_decompiler.cc b/runtime/dex_to_dex_decompiler.cc
index a5248e6..aff9b47 100644
--- a/runtime/dex_to_dex_decompiler.cc
+++ b/runtime/dex_to_dex_decompiler.cc
@@ -187,7 +187,6 @@
LOG(FATAL) << "Failed to use all values in quickening info."
<< " Actual: " << std::hex << quicken_index_
<< " Expected: " << quicken_info_.NumIndices();
- return false;
}
}
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index b6adcf0..8737f3f 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2515,7 +2515,7 @@
ArtMethod* caller_method = QuickArgumentVisitor::GetCallingMethod(sp);
ArtMethod* method = FindMethodFast<type, access_check>(method_idx, this_object, caller_method);
if (UNLIKELY(method == nullptr)) {
- const DexFile* dex_file = caller_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
+ const DexFile* dex_file = caller_method->GetDexFile();
uint32_t shorty_len;
const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx), &shorty_len);
{
@@ -2648,7 +2648,7 @@
dex_method_idx = instr.VRegB_3rc();
}
- const DexFile& dex_file = caller_method->GetDeclaringClass()->GetDexFile();
+ const DexFile& dex_file = *caller_method->GetDexFile();
uint32_t shorty_len;
const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(dex_method_idx),
&shorty_len);
diff --git a/runtime/gc/allocation_record.cc b/runtime/gc/allocation_record.cc
index e11fa5c..80e3394 100644
--- a/runtime/gc/allocation_record.cc
+++ b/runtime/gc/allocation_record.cc
@@ -184,34 +184,6 @@
new_record_condition_.Broadcast(Thread::Current());
}
-class AllocRecordStackVisitor : public StackVisitor {
- public:
- AllocRecordStackVisitor(Thread* thread, size_t max_depth, AllocRecordStackTrace* trace_out)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- max_depth_(max_depth),
- trace_(trace_out) {}
-
- // TODO: Enable annotalysis. We know lock is held in constructor, but abstraction confuses
- // annotalysis.
- bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
- if (trace_->GetDepth() >= max_depth_) {
- return false;
- }
- ArtMethod* m = GetMethod();
- // m may be null if we have inlined methods of unresolved classes. b/27858645
- if (m != nullptr && !m->IsRuntimeMethod()) {
- m = m->GetInterfaceMethodIfProxy(kRuntimePointerSize);
- trace_->AddStackElement(AllocRecordStackTraceElement(m, GetDexPc()));
- }
- return true;
- }
-
- private:
- const size_t max_depth_;
- AllocRecordStackTrace* const trace_;
-};
-
void AllocRecordObjectMap::SetAllocTrackingEnabled(bool enable) {
Thread* self = Thread::Current();
Heap* heap = Runtime::Current()->GetHeap();
@@ -268,11 +240,26 @@
// Get stack trace outside of lock in case there are allocations during the stack walk.
// b/27858645.
AllocRecordStackTrace trace;
- AllocRecordStackVisitor visitor(self, max_stack_depth_, /*out*/ &trace);
{
StackHandleScope<1> hs(self);
auto obj_wrapper = hs.NewHandleWrapper(obj);
- visitor.WalkStack();
+
+ StackVisitor::WalkStack(
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (trace.GetDepth() >= max_stack_depth_) {
+ return false;
+ }
+ ArtMethod* m = stack_visitor->GetMethod();
+ // m may be null if we have inlined methods of unresolved classes. b/27858645
+ if (m != nullptr && !m->IsRuntimeMethod()) {
+ m = m->GetInterfaceMethodIfProxy(kRuntimePointerSize);
+ trace.AddStackElement(AllocRecordStackTraceElement(m, stack_visitor->GetDexPc()));
+ }
+ return true;
+ },
+ self,
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
}
MutexLock mu(self, *Locks::alloc_tracker_lock_);
diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc
index 2774e26..21cae93 100644
--- a/runtime/gc/space/region_space.cc
+++ b/runtime/gc/space/region_space.cc
@@ -17,6 +17,7 @@
#include "bump_pointer_space-inl.h"
#include "bump_pointer_space.h"
#include "base/dumpable.h"
+#include "base/logging.h"
#include "gc/accounting/read_barrier_table.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
diff --git a/runtime/gc/verification.cc b/runtime/gc/verification.cc
index 47c54bd..8670a22 100644
--- a/runtime/gc/verification.cc
+++ b/runtime/gc/verification.cc
@@ -21,6 +21,7 @@
#include "art_field-inl.h"
#include "base/file_utils.h"
+#include "base/logging.h"
#include "mirror/class-inl.h"
#include "mirror/object-refvisitor-inl.h"
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index cbcaaef..12f1522 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -18,6 +18,8 @@
#include <sstream>
+#include <android-base/logging.h>
+
#include "arch/context.h"
#include "art_field-inl.h"
#include "art_method-inl.h"
@@ -1355,65 +1357,66 @@
}
// Try to get the shorty of a runtime method if it's an invocation stub.
-struct RuntimeMethodShortyVisitor : public StackVisitor {
- explicit RuntimeMethodShortyVisitor(Thread* thread)
- : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- shorty('V') {}
-
- static uint16_t GetMethodIndexOfInvoke(ArtMethod* caller,
- const Instruction& inst,
- uint32_t dex_pc)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- switch (inst.Opcode()) {
- case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
- case Instruction::INVOKE_VIRTUAL_QUICK: {
- uint16_t method_idx = caller->GetIndexFromQuickening(dex_pc);
- CHECK_NE(method_idx, DexFile::kDexNoIndex16);
- return method_idx;
- }
- default: {
- return inst.VRegB();
- }
- }
- }
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* m = GetMethod();
- if (m == nullptr || m->IsRuntimeMethod()) {
- return true;
- }
- // The first Java method.
- if (m->IsNative()) {
- // Use JNI method's shorty for the jni stub.
- shorty = m->GetShorty()[0];
- } else if (m->IsProxyMethod()) {
- // Proxy method just invokes its proxied method via
- // art_quick_proxy_invoke_handler.
- shorty = m->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty()[0];
- } else {
- const Instruction& instr = m->DexInstructions().InstructionAt(GetDexPc());
- if (instr.IsInvoke()) {
- uint16_t method_index = GetMethodIndexOfInvoke(m, instr, GetDexPc());
- const DexFile* dex_file = m->GetDexFile();
- if (interpreter::IsStringInit(dex_file, method_index)) {
- // Invoking string init constructor is turned into invoking
- // StringFactory.newStringFromChars() which returns a string.
- shorty = 'L';
- } else {
- shorty = dex_file->GetMethodShorty(method_index)[0];
+static char GetRuntimeMethodShorty(Thread* thread) REQUIRES_SHARED(Locks::mutator_lock_) {
+ char shorty = 'V';
+ StackVisitor::WalkStack(
+ [&shorty](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = stack_visitor->GetMethod();
+ if (m == nullptr || m->IsRuntimeMethod()) {
+ return true;
}
- } else {
- // It could be that a non-invoke opcode invokes a stub, which in turn
- // invokes Java code. In such cases, we should never expect a return
- // value from the stub.
- }
- }
- // Stop stack walking since we've seen a Java frame.
- return false;
- }
+ // The first Java method.
+ if (m->IsNative()) {
+ // Use JNI method's shorty for the jni stub.
+ shorty = m->GetShorty()[0];
+ } else if (m->IsProxyMethod()) {
+ // Proxy method just invokes its proxied method via
+ // art_quick_proxy_invoke_handler.
+ shorty = m->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty()[0];
+ } else {
+ const Instruction& instr = m->DexInstructions().InstructionAt(stack_visitor->GetDexPc());
+ if (instr.IsInvoke()) {
+ auto get_method_index_fn = [](ArtMethod* caller,
+ const Instruction& inst,
+ uint32_t dex_pc)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ switch (inst.Opcode()) {
+ case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
+ case Instruction::INVOKE_VIRTUAL_QUICK: {
+ uint16_t method_idx = caller->GetIndexFromQuickening(dex_pc);
+ CHECK_NE(method_idx, DexFile::kDexNoIndex16);
+ return method_idx;
+ }
+ default: {
+ return static_cast<uint16_t>(inst.VRegB());
+ }
+ }
+ };
- char shorty;
-};
+ uint16_t method_index = get_method_index_fn(m, instr, stack_visitor->GetDexPc());
+ const DexFile* dex_file = m->GetDexFile();
+ if (interpreter::IsStringInit(dex_file, method_index)) {
+ // Invoking string init constructor is turned into invoking
+ // StringFactory.newStringFromChars() which returns a string.
+ shorty = 'L';
+ } else {
+ shorty = dex_file->GetMethodShorty(method_index)[0];
+ }
+
+ } else {
+ // It could be that a non-invoke opcode invokes a stub, which in turn
+ // invokes Java code. In such cases, we should never expect a return
+ // value from the stub.
+ }
+ }
+ // Stop stack walking since we've seen a Java frame.
+ return false;
+ },
+ thread,
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+ return shorty;
+}
TwoWordReturn Instrumentation::PopInstrumentationStackFrame(Thread* self,
uintptr_t* return_pc,
@@ -1447,9 +1450,7 @@
// for clinit, we need to pass return results to the caller.
// We need the correct shorty to decide whether we need to pass the return
// result for deoptimization below.
- RuntimeMethodShortyVisitor visitor(self);
- visitor.WalkStack();
- return_shorty = visitor.shorty;
+ return_shorty = GetRuntimeMethodShorty(self);
} else {
// Some runtime methods such as allocations, unresolved field getters, etc.
// have return value. We don't need to set return_value since MethodExitEvent()
diff --git a/runtime/jdwp_provider.h b/runtime/jdwp_provider.h
index c4f1989..9579513 100644
--- a/runtime/jdwp_provider.h
+++ b/runtime/jdwp_provider.h
@@ -20,8 +20,6 @@
#include <ios>
#include "base/globals.h"
-#include "base/macros.h"
-#include "base/logging.h"
namespace art {
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 28978c5..97887cc 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -18,7 +18,8 @@
#include <sstream>
-#include "android-base/unique_fd.h"
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
#include "arch/context.h"
#include "art_method-inl.h"
@@ -1304,31 +1305,6 @@
}
}
-class MarkCodeVisitor final : public StackVisitor {
- public:
- MarkCodeVisitor(Thread* thread_in, JitCodeCache* code_cache_in, CodeCacheBitmap* bitmap)
- : StackVisitor(thread_in, nullptr, StackVisitor::StackWalkKind::kSkipInlinedFrames),
- code_cache_(code_cache_in),
- bitmap_(bitmap) {}
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
- if (method_header == nullptr) {
- return true;
- }
- const void* code = method_header->GetCode();
- if (code_cache_->ContainsPc(code)) {
- // Use the atomic set version, as multiple threads are executing this code.
- bitmap_->AtomicTestAndSet(FromCodeToAllocation(code));
- }
- return true;
- }
-
- private:
- JitCodeCache* const code_cache_;
- CodeCacheBitmap* const bitmap_;
-};
-
class MarkCodeClosure final : public Closure {
public:
MarkCodeClosure(JitCodeCache* code_cache, CodeCacheBitmap* bitmap, Barrier* barrier)
@@ -1337,8 +1313,24 @@
void Run(Thread* thread) override REQUIRES_SHARED(Locks::mutator_lock_) {
ScopedTrace trace(__PRETTY_FUNCTION__);
DCHECK(thread == Thread::Current() || thread->IsSuspended());
- MarkCodeVisitor visitor(thread, code_cache_, bitmap_);
- visitor.WalkStack();
+ StackVisitor::WalkStack(
+ [&](const art::StackVisitor* stack_visitor) {
+ const OatQuickMethodHeader* method_header =
+ stack_visitor->GetCurrentOatQuickMethodHeader();
+ if (method_header == nullptr) {
+ return true;
+ }
+ const void* code = method_header->GetCode();
+ if (code_cache_->ContainsPc(code)) {
+ // Use the atomic set version, as multiple threads are executing this code.
+ bitmap_->AtomicTestAndSet(FromCodeToAllocation(code));
+ }
+ return true;
+ },
+ thread,
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kSkipInlinedFrames);
+
if (kIsDebugBuild) {
// The stack walking code queries the side instrumentation stack if it
// sees an instrumentation exit pc, so the JIT code of methods in that stack
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index df2a8e2..6479283 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -277,43 +277,6 @@
obj_ = GcRoot<mirror::Object>(object);
}
-// Note: Adapted from CurrentMethodVisitor in thread.cc. We must not resolve here.
-
-struct NthCallerWithDexPcVisitor final : public StackVisitor {
- explicit NthCallerWithDexPcVisitor(Thread* thread, size_t frame)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- method_(nullptr),
- dex_pc_(0),
- current_frame_number_(0),
- wanted_frame_number_(frame) {}
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* m = GetMethod();
- if (m == nullptr || m->IsRuntimeMethod()) {
- // Runtime method, upcall, or resolution issue. Skip.
- return true;
- }
-
- // Is this the requested frame?
- if (current_frame_number_ == wanted_frame_number_) {
- method_ = m;
- dex_pc_ = GetDexPc(/* abort_on_failure=*/ false);
- return false;
- }
-
- // Look for more.
- current_frame_number_++;
- return true;
- }
-
- ArtMethod* method_;
- uint32_t dex_pc_;
-
- private:
- size_t current_frame_number_;
- const size_t wanted_frame_number_;
-};
-
// This function is inlined and just helps to not have the VLOG and ATRACE check at all the
// potential tracing points.
void Monitor::AtraceMonitorLock(Thread* self, mirror::Object* obj, bool is_wait) {
@@ -326,13 +289,41 @@
// Wait() requires a deeper call stack to be useful. Otherwise you'll see "Waiting at
// Object.java". Assume that we'll wait a nontrivial amount, so it's OK to do a longer
// stack walk than if !is_wait.
- NthCallerWithDexPcVisitor visitor(self, is_wait ? 1U : 0U);
- visitor.WalkStack(false);
+ const size_t wanted_frame_number = is_wait ? 1U : 0U;
+
+ ArtMethod* method = nullptr;
+ uint32_t dex_pc = 0u;
+
+ size_t current_frame_number = 0u;
+ StackVisitor::WalkStack(
+ // Note: Adapted from CurrentMethodVisitor in thread.cc. We must not resolve here.
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = stack_visitor->GetMethod();
+ if (m == nullptr || m->IsRuntimeMethod()) {
+ // Runtime method, upcall, or resolution issue. Skip.
+ return true;
+ }
+
+ // Is this the requested frame?
+ if (current_frame_number == wanted_frame_number) {
+ method = m;
+ dex_pc = stack_visitor->GetDexPc(false /* abort_on_error*/);
+ return false;
+ }
+
+ // Look for more.
+ current_frame_number++;
+ return true;
+ },
+ self,
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+
const char* prefix = is_wait ? "Waiting on " : "Locking ";
const char* filename;
int32_t line_number;
- TranslateLocation(visitor.method_, visitor.dex_pc_, &filename, &line_number);
+ TranslateLocation(method, dex_pc, &filename, &line_number);
// It would be nice to have a stable "ID" for the object here. However, the only stable thing
// would be the identity hashcode. But we cannot use IdentityHashcode here: For one, there are
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index afdfefa..d4e3d54 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -154,46 +154,36 @@
DISALLOW_COPY_AND_ASSIGN(CatchBlockStackVisitor);
};
-// Counts instrumentation stack frame prior to catch handler or upcall.
-class InstrumentationStackVisitor : public StackVisitor {
- public:
- InstrumentationStackVisitor(Thread* self, size_t frame_depth)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(self, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- frame_depth_(frame_depth),
- instrumentation_frames_to_pop_(0) {
- CHECK_NE(frame_depth_, kInvalidFrameDepth);
- }
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- size_t current_frame_depth = GetFrameDepth();
- if (current_frame_depth < frame_depth_) {
- CHECK(GetMethod() != nullptr);
- if (UNLIKELY(reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) == GetReturnPc())) {
- if (!IsInInlinedFrame()) {
- // We do not count inlined frames, because we do not instrument them. The reason we
- // include them in the stack walking is the check against `frame_depth_`, which is
- // given to us by a visitor that visits inlined frames.
- ++instrumentation_frames_to_pop_;
+static size_t GetInstrumentationFramesToPop(Thread* self, size_t frame_depth)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ CHECK_NE(frame_depth, kInvalidFrameDepth);
+ size_t instrumentation_frames_to_pop = 0;
+ StackVisitor::WalkStack(
+ [&](art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ size_t current_frame_depth = stack_visitor->GetFrameDepth();
+ if (current_frame_depth < frame_depth) {
+ CHECK(stack_visitor->GetMethod() != nullptr);
+ if (UNLIKELY(reinterpret_cast<uintptr_t>(GetQuickInstrumentationExitPc()) ==
+ stack_visitor->GetReturnPc())) {
+ if (!stack_visitor->IsInInlinedFrame()) {
+ // We do not count inlined frames, because we do not instrument them. The reason we
+ // include them in the stack walking is the check against `frame_depth_`, which is
+ // given to us by a visitor that visits inlined frames.
+ ++instrumentation_frames_to_pop;
+ }
+ }
+ return true;
}
- }
- return true;
- } else {
- // We reached the frame of the catch handler or the upcall.
- return false;
- }
- }
-
- size_t GetInstrumentationFramesToPop() const {
- return instrumentation_frames_to_pop_;
- }
-
- private:
- const size_t frame_depth_;
- size_t instrumentation_frames_to_pop_;
-
- DISALLOW_COPY_AND_ASSIGN(InstrumentationStackVisitor);
-};
+ // We reached the frame of the catch handler or the upcall.
+ return false;
+ },
+ self,
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames,
+ /* check_suspended */ true,
+ /* include_transitions */ true);
+ return instrumentation_frames_to_pop;
+}
// Finds the appropriate exception catch after calling all method exit instrumentation functions.
// Note that this might change the exception being thrown.
@@ -229,9 +219,8 @@
// Figure out how many of those frames have instrumentation we need to remove (Should be the
// exact same as number of new_pop_count if there aren't inlined frames).
- InstrumentationStackVisitor instrumentation_visitor(self_, handler_frame_depth_);
- instrumentation_visitor.WalkStack(true);
- size_t instrumentation_frames_to_pop = instrumentation_visitor.GetInstrumentationFramesToPop();
+ size_t instrumentation_frames_to_pop =
+ GetInstrumentationFramesToPop(self_, handler_frame_depth_);
if (kDebugExceptionDelivery) {
if (*handler_quick_frame_ == nullptr) {
@@ -647,10 +636,8 @@
DCHECK(is_deoptimization_) << "Non-deoptimization handlers should use FindCatch";
uintptr_t return_pc = 0;
if (method_tracing_active_) {
- InstrumentationStackVisitor visitor(self_, handler_frame_depth_);
- visitor.WalkStack(true);
-
- size_t instrumentation_frames_to_pop = visitor.GetInstrumentationFramesToPop();
+ size_t instrumentation_frames_to_pop =
+ GetInstrumentationFramesToPop(self_, handler_frame_depth_);
instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
return_pc = instrumentation->PopFramesForDeoptimization(self_, instrumentation_frames_to_pop);
}
@@ -671,53 +658,41 @@
UNREACHABLE();
}
-// Prints out methods with their type of frame.
-class DumpFramesWithTypeStackVisitor final : public StackVisitor {
- public:
- explicit DumpFramesWithTypeStackVisitor(Thread* self, bool show_details = false)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(self, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- show_details_(show_details) {}
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* method = GetMethod();
- if (show_details_) {
- LOG(INFO) << "|> pc = " << std::hex << GetCurrentQuickFramePc();
- LOG(INFO) << "|> addr = " << std::hex << reinterpret_cast<uintptr_t>(GetCurrentQuickFrame());
- if (GetCurrentQuickFrame() != nullptr && method != nullptr) {
- LOG(INFO) << "|> ret = " << std::hex << GetReturnPc();
- }
- }
- if (method == nullptr) {
- // Transition, do go on, we want to unwind over bridges, all the way.
- if (show_details_) {
- LOG(INFO) << "N <transition>";
- }
- return true;
- } else if (method->IsRuntimeMethod()) {
- if (show_details_) {
- LOG(INFO) << "R " << method->PrettyMethod(true);
- }
- return true;
- } else {
- bool is_shadow = GetCurrentShadowFrame() != nullptr;
- LOG(INFO) << (is_shadow ? "S" : "Q")
- << ((!is_shadow && IsInInlinedFrame()) ? "i" : " ")
- << " "
- << method->PrettyMethod(true);
- return true; // Go on.
- }
- }
-
- private:
- bool show_details_;
-
- DISALLOW_COPY_AND_ASSIGN(DumpFramesWithTypeStackVisitor);
-};
-
void QuickExceptionHandler::DumpFramesWithType(Thread* self, bool details) {
- DumpFramesWithTypeStackVisitor visitor(self, details);
- visitor.WalkStack(true);
+ StackVisitor::WalkStack(
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* method = stack_visitor->GetMethod();
+ if (details) {
+ LOG(INFO) << "|> pc = " << std::hex << stack_visitor->GetCurrentQuickFramePc();
+ LOG(INFO) << "|> addr = " << std::hex
+ << reinterpret_cast<uintptr_t>(stack_visitor->GetCurrentQuickFrame());
+ if (stack_visitor->GetCurrentQuickFrame() != nullptr && method != nullptr) {
+ LOG(INFO) << "|> ret = " << std::hex << stack_visitor->GetReturnPc();
+ }
+ }
+ if (method == nullptr) {
+ // Transition, do go on, we want to unwind over bridges, all the way.
+ if (details) {
+ LOG(INFO) << "N <transition>";
+ }
+ return true;
+ } else if (method->IsRuntimeMethod()) {
+ if (details) {
+ LOG(INFO) << "R " << method->PrettyMethod(true);
+ }
+ return true;
+ } else {
+ bool is_shadow = stack_visitor->GetCurrentShadowFrame() != nullptr;
+ LOG(INFO) << (is_shadow ? "S" : "Q")
+ << ((!is_shadow && stack_visitor->IsInInlinedFrame()) ? "i" : " ")
+ << " "
+ << method->PrettyMethod(true);
+ return true; // Go on.
+ }
+ },
+ self,
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
}
} // namespace art
diff --git a/runtime/runtime_options.h b/runtime/runtime_options.h
index 3f5e776..39b44e7 100644
--- a/runtime/runtime_options.h
+++ b/runtime/runtime_options.h
@@ -23,7 +23,6 @@
#include <vector>
#include "arch/instruction_set.h"
-#include "base/logging.h"
#include "base/variant_map.h"
#include "cmdline_types.h" // TODO: don't need to include this file here
#include "gc/collector_type.h"
diff --git a/runtime/stack.h b/runtime/stack.h
index 02578d2..9d30115 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -143,6 +143,36 @@
template <CountTransitions kCount = CountTransitions::kYes>
void WalkStack(bool include_transitions = false) REQUIRES_SHARED(Locks::mutator_lock_);
+ // Convenience helper function to walk the stack with a lambda as a visitor.
+ template <CountTransitions kCountTransitions = CountTransitions::kYes,
+ typename T>
+ ALWAYS_INLINE static void WalkStack(const T& fn,
+ Thread* thread,
+ Context* context,
+ StackWalkKind walk_kind,
+ bool check_suspended = true,
+ bool include_transitions = false)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ class LambdaStackVisitor : public StackVisitor {
+ public:
+ LambdaStackVisitor(const T& fn,
+ Thread* thread,
+ Context* context,
+ StackWalkKind walk_kind,
+ bool check_suspended = true)
+ : StackVisitor(thread, context, walk_kind, check_suspended), fn_(fn) {}
+
+ bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
+ return fn_(this);
+ }
+
+ private:
+ T fn_;
+ };
+ LambdaStackVisitor visitor(fn, thread, context, walk_kind, check_suspended);
+ visitor.template WalkStack<kCountTransitions>(include_transitions);
+ }
+
Thread* GetThread() const {
return thread_;
}
diff --git a/runtime/thread.cc b/runtime/thread.cc
index e9fed76..33cd9bb 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -3607,42 +3607,34 @@
return result;
}
-ArtMethod* Thread::GetCurrentMethod(uint32_t* dex_pc,
+ArtMethod* Thread::GetCurrentMethod(uint32_t* dex_pc_out,
bool check_suspended,
bool abort_on_error) const {
// Note: this visitor may return with a method set, but dex_pc_ being DexFile:kDexNoIndex. This is
// so we don't abort in a special situation (thinlocked monitor) when dumping the Java
// stack.
- struct CurrentMethodVisitor final : public StackVisitor {
- CurrentMethodVisitor(Thread* thread, bool check_suspended, bool abort_on_error)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread,
- /* context= */nullptr,
- StackVisitor::StackWalkKind::kIncludeInlinedFrames,
- check_suspended),
- method_(nullptr),
- dex_pc_(0),
- abort_on_error_(abort_on_error) {}
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* m = GetMethod();
- if (m->IsRuntimeMethod()) {
- // Continue if this is a runtime method.
- return true;
- }
- method_ = m;
- dex_pc_ = GetDexPc(abort_on_error_);
- return false;
- }
- ArtMethod* method_;
- uint32_t dex_pc_;
- const bool abort_on_error_;
- };
- CurrentMethodVisitor visitor(const_cast<Thread*>(this), check_suspended, abort_on_error);
- visitor.WalkStack(false);
- if (dex_pc != nullptr) {
- *dex_pc = visitor.dex_pc_;
+ ArtMethod* method = nullptr;
+ uint32_t dex_pc = dex::kDexNoIndex;
+ StackVisitor::WalkStack(
+ [&](const StackVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = visitor->GetMethod();
+ if (m->IsRuntimeMethod()) {
+ // Continue if this is a runtime method.
+ return true;
+ }
+ method = m;
+ dex_pc = visitor->GetDexPc(abort_on_error);
+ return false;
+ },
+ const_cast<Thread*>(this),
+ /* context= */ nullptr,
+ StackVisitor::StackWalkKind::kIncludeInlinedFrames,
+ check_suspended);
+
+ if (dex_pc_out != nullptr) {
+ *dex_pc_out = dex_pc;
}
- return visitor.method_;
+ return method;
}
bool Thread::HoldsLock(ObjPtr<mirror::Object> object) const {
diff --git a/runtime/ti/agent.cc b/runtime/ti/agent.cc
index 97c39bb..033c8ac 100644
--- a/runtime/ti/agent.cc
+++ b/runtime/ti/agent.cc
@@ -20,6 +20,7 @@
#include "nativehelper/scoped_local_ref.h"
#include "nativeloader/native_loader.h"
+#include "base/logging.h"
#include "base/strlcpy.h"
#include "jni/java_vm_ext.h"
#include "runtime.h"
diff --git a/runtime/ti/agent.h b/runtime/ti/agent.h
index faf76a1..598c8ff 100644
--- a/runtime/ti/agent.h
+++ b/runtime/ti/agent.h
@@ -22,7 +22,8 @@
#include <memory>
-#include "base/logging.h"
+#include <android-base/logging.h>
+#include <android-base/macros.h>
namespace art {
namespace ti {
diff --git a/runtime/trace.cc b/runtime/trace.cc
index ad58c2e..f6c36cf 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -58,32 +58,6 @@
static constexpr uint8_t kOpNewThread = 2U;
static constexpr uint8_t kOpTraceSummary = 3U;
-class BuildStackTraceVisitor : public StackVisitor {
- public:
- explicit BuildStackTraceVisitor(Thread* thread)
- : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- method_trace_(Trace::AllocStackTrace()) {}
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* m = GetMethod();
- // Ignore runtime frames (in particular callee save).
- if (!m->IsRuntimeMethod()) {
- method_trace_->push_back(m);
- }
- return true;
- }
-
- // Returns a stack trace where the topmost frame corresponds with the first element of the vector.
- std::vector<ArtMethod*>* GetStackTrace() const {
- return method_trace_;
- }
-
- private:
- std::vector<ArtMethod*>* const method_trace_;
-
- DISALLOW_COPY_AND_ASSIGN(BuildStackTraceVisitor);
-};
-
static const char kTraceTokenChar = '*';
static const uint16_t kTraceHeaderLength = 32;
static const uint32_t kTraceMagicValue = 0x574f4c53;
@@ -228,9 +202,19 @@
}
static void GetSample(Thread* thread, void* arg) REQUIRES_SHARED(Locks::mutator_lock_) {
- BuildStackTraceVisitor build_trace_visitor(thread);
- build_trace_visitor.WalkStack();
- std::vector<ArtMethod*>* stack_trace = build_trace_visitor.GetStackTrace();
+ std::vector<ArtMethod*>* const stack_trace = Trace::AllocStackTrace();
+ StackVisitor::WalkStack(
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = stack_visitor->GetMethod();
+ // Ignore runtime frames (in particular callee save).
+ if (!m->IsRuntimeMethod()) {
+ stack_trace->push_back(m);
+ }
+ return true;
+ },
+ thread,
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
Trace* the_trace = reinterpret_cast<Trace*>(arg);
the_trace->CompareAndUpdateStackTrace(thread, stack_trace);
}
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index 985d273..0cb220e 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -30,6 +30,7 @@
#include <backtrace/Backtrace.h>
#include "base/file_utils.h"
+#include "base/logging.h"
#include "base/macros.h"
#include "base/utils.h"
#include "gc/heap.h"
diff --git a/test/461-get-reference-vreg/get_reference_vreg_jni.cc b/test/461-get-reference-vreg/get_reference_vreg_jni.cc
index ddc86df..817a647 100644
--- a/test/461-get-reference-vreg/get_reference_vreg_jni.cc
+++ b/test/461-get-reference-vreg/get_reference_vreg_jni.cc
@@ -25,62 +25,50 @@
namespace {
-class TestVisitor : public StackVisitor {
- public:
- TestVisitor(Thread* thread, Context* context, mirror::Object* this_value)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- this_value_(this_value),
- found_method_index_(0) {}
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* m = GetMethod();
- std::string m_name(m->GetName());
-
- if (m_name.compare("$noinline$testThisWithInstanceCall") == 0) {
- found_method_index_ = 1;
- uint32_t value = 0;
- CHECK(GetVReg(m, 1, kReferenceVReg, &value));
- CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value_);
- CHECK_EQ(GetThisObject(), this_value_);
- } else if (m_name.compare("$noinline$testThisWithStaticCall") == 0) {
- found_method_index_ = 2;
- uint32_t value = 0;
- CHECK(GetVReg(m, 1, kReferenceVReg, &value));
- } else if (m_name.compare("$noinline$testParameter") == 0) {
- found_method_index_ = 3;
- uint32_t value = 0;
- CHECK(GetVReg(m, 1, kReferenceVReg, &value));
- } else if (m_name.compare("$noinline$testObjectInScope") == 0) {
- found_method_index_ = 4;
- uint32_t value = 0;
- CHECK(GetVReg(m, 0, kReferenceVReg, &value));
- }
-
- return true;
- }
-
- mirror::Object* this_value_;
-
- // Value returned to Java to ensure the methods testSimpleVReg and testPairVReg
- // have been found and tested.
- jint found_method_index_;
-};
-
-extern "C" JNIEXPORT jint JNICALL Java_Main_doNativeCallRef(JNIEnv*, jobject value) {
+jint FindMethodIndex(jobject this_value_jobj) {
ScopedObjectAccess soa(Thread::Current());
std::unique_ptr<Context> context(Context::Create());
- TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object>(value).Ptr());
- visitor.WalkStack();
- return visitor.found_method_index_;
+ ObjPtr<mirror::Object> this_value = soa.Decode<mirror::Object>(this_value_jobj);
+ jint found_method_index = 0;
+ StackVisitor::WalkStack(
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = stack_visitor->GetMethod();
+ std::string m_name(m->GetName());
+
+ if (m_name.compare("$noinline$testThisWithInstanceCall") == 0) {
+ found_method_index = 1;
+ uint32_t value = 0;
+ CHECK(stack_visitor->GetVReg(m, 1, kReferenceVReg, &value));
+ CHECK_EQ(reinterpret_cast<mirror::Object*>(value), this_value);
+ CHECK_EQ(stack_visitor->GetThisObject(), this_value);
+ } else if (m_name.compare("$noinline$testThisWithStaticCall") == 0) {
+ found_method_index = 2;
+ uint32_t value = 0;
+ CHECK(stack_visitor->GetVReg(m, 1, kReferenceVReg, &value));
+ } else if (m_name.compare("$noinline$testParameter") == 0) {
+ found_method_index = 3;
+ uint32_t value = 0;
+ CHECK(stack_visitor->GetVReg(m, 1, kReferenceVReg, &value));
+ } else if (m_name.compare("$noinline$testObjectInScope") == 0) {
+ found_method_index = 4;
+ uint32_t value = 0;
+ CHECK(stack_visitor->GetVReg(m, 0, kReferenceVReg, &value));
+ }
+
+ return true;
+ },
+ soa.Self(),
+ context.get(),
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+ return found_method_index;
+}
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_doNativeCallRef(JNIEnv*, jobject value) {
+ return FindMethodIndex(value);
}
extern "C" JNIEXPORT jint JNICALL Java_Main_doStaticNativeCallRef(JNIEnv*, jclass) {
- ScopedObjectAccess soa(Thread::Current());
- std::unique_ptr<Context> context(Context::Create());
- TestVisitor visitor(soa.Self(), context.get(), nullptr);
- visitor.WalkStack();
- return visitor.found_method_index_;
+ return FindMethodIndex(nullptr);
}
} // namespace
diff --git a/test/543-env-long-ref/env_long_ref.cc b/test/543-env-long-ref/env_long_ref.cc
index 165f5bf..1885f8d 100644
--- a/test/543-env-long-ref/env_long_ref.cc
+++ b/test/543-env-long-ref/env_long_ref.cc
@@ -23,44 +23,28 @@
namespace art {
-namespace {
-
-class TestVisitor : public StackVisitor {
- public:
- TestVisitor(const ScopedObjectAccess& soa, Context* context, jobject expected_value)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(soa.Self(), context, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- expected_value_(expected_value),
- found_(false),
- soa_(soa) {}
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* m = GetMethod();
- std::string m_name(m->GetName());
-
- if (m_name == "testCase") {
- found_ = true;
- uint32_t value = 0;
- CHECK(GetVReg(m, 1, kReferenceVReg, &value));
- CHECK_EQ(reinterpret_cast<mirror::Object*>(value),
- soa_.Decode<mirror::Object>(expected_value_).Ptr());
- }
- return true;
- }
-
- jobject expected_value_;
- bool found_;
- const ScopedObjectAccess& soa_;
-};
-
-} // namespace
-
extern "C" JNIEXPORT void JNICALL Java_Main_lookForMyRegisters(JNIEnv*, jclass, jobject value) {
ScopedObjectAccess soa(Thread::Current());
std::unique_ptr<Context> context(Context::Create());
- TestVisitor visitor(soa, context.get(), value);
- visitor.WalkStack();
- CHECK(visitor.found_);
+ bool found = false;
+ StackVisitor::WalkStack(
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = stack_visitor->GetMethod();
+ std::string m_name(m->GetName());
+
+ if (m_name == "testCase") {
+ found = true;
+ uint32_t stack_value = 0;
+ CHECK(stack_visitor->GetVReg(m, 1, kReferenceVReg, &stack_value));
+ CHECK_EQ(reinterpret_cast<mirror::Object*>(stack_value),
+ soa.Decode<mirror::Object>(value).Ptr());
+ }
+ return true;
+ },
+ soa.Self(),
+ context.get(),
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+ CHECK(found);
}
} // namespace art
diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc
index 7b88842..b2b3634 100644
--- a/test/570-checker-osr/osr.cc
+++ b/test/570-checker-osr/osr.cc
@@ -23,39 +23,33 @@
#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "stack_map.h"
+#include "thread-current-inl.h"
namespace art {
-class OsrVisitor : public StackVisitor {
- public:
- explicit OsrVisitor(Thread* thread, const char* method_name)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- method_name_(method_name),
- in_osr_method_(false),
- in_interpreter_(false) {}
+namespace {
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* m = GetMethod();
- std::string m_name(m->GetName());
+template <typename Handler>
+void ProcessMethodWithName(JNIEnv* env, jstring method_name, const Handler& handler) {
+ ScopedUtfChars chars(env, method_name);
+ CHECK(chars.c_str() != nullptr);
+ ScopedObjectAccess soa(Thread::Current());
+ StackVisitor::WalkStack(
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ std::string m_name(stack_visitor->GetMethod()->GetName());
- if (m_name.compare(method_name_) == 0) {
- const OatQuickMethodHeader* header =
- Runtime::Current()->GetJit()->GetCodeCache()->LookupOsrMethodHeader(m);
- if (header != nullptr && header == GetCurrentOatQuickMethodHeader()) {
- in_osr_method_ = true;
- } else if (IsShadowFrame()) {
- in_interpreter_ = true;
- }
- return false;
- }
- return true;
- }
+ if (m_name.compare(chars.c_str()) == 0) {
+ handler(stack_visitor);
+ return false;
+ }
+ return true;
+ },
+ soa.Self(),
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+}
- const char* const method_name_;
- bool in_osr_method_;
- bool in_interpreter_;
-};
+} // namespace
extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInOsrCode(JNIEnv* env,
jclass,
@@ -65,12 +59,19 @@
// Just return true for non-jit configurations to stop the infinite loop.
return JNI_TRUE;
}
- ScopedUtfChars chars(env, method_name);
- CHECK(chars.c_str() != nullptr);
- ScopedObjectAccess soa(Thread::Current());
- OsrVisitor visitor(soa.Self(), chars.c_str());
- visitor.WalkStack();
- return visitor.in_osr_method_;
+ bool in_osr_code = false;
+ ProcessMethodWithName(
+ env,
+ method_name,
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = stack_visitor->GetMethod();
+ const OatQuickMethodHeader* header =
+ Runtime::Current()->GetJit()->GetCodeCache()->LookupOsrMethodHeader(m);
+ if (header != nullptr && header == stack_visitor->GetCurrentOatQuickMethodHeader()) {
+ in_osr_code = true;
+ }
+ });
+ return in_osr_code;
}
extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInInterpreter(JNIEnv* env,
@@ -80,86 +81,56 @@
// The return value is irrelevant if we're not using JIT.
return false;
}
- ScopedUtfChars chars(env, method_name);
- CHECK(chars.c_str() != nullptr);
- ScopedObjectAccess soa(Thread::Current());
- OsrVisitor visitor(soa.Self(), chars.c_str());
- visitor.WalkStack();
- return visitor.in_interpreter_;
+ bool in_interpreter = false;
+ ProcessMethodWithName(
+ env,
+ method_name,
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = stack_visitor->GetMethod();
+ const OatQuickMethodHeader* header =
+ Runtime::Current()->GetJit()->GetCodeCache()->LookupOsrMethodHeader(m);
+ if ((header == nullptr || header != stack_visitor->GetCurrentOatQuickMethodHeader()) &&
+ stack_visitor->IsShadowFrame()) {
+ in_interpreter = true;
+ }
+ });
+ return in_interpreter;
}
-class ProfilingInfoVisitor : public StackVisitor {
- public:
- explicit ProfilingInfoVisitor(Thread* thread, const char* method_name)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- method_name_(method_name) {}
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* m = GetMethod();
- std::string m_name(m->GetName());
-
- if (m_name.compare(method_name_) == 0) {
- ProfilingInfo::Create(Thread::Current(), m, /* retry_allocation */ true);
- return false;
- }
- return true;
- }
-
- const char* const method_name_;
-};
-
extern "C" JNIEXPORT void JNICALL Java_Main_ensureHasProfilingInfo(JNIEnv* env,
jclass,
jstring method_name) {
if (!Runtime::Current()->UseJitCompilation()) {
return;
}
- ScopedUtfChars chars(env, method_name);
- CHECK(chars.c_str() != nullptr);
- ScopedObjectAccess soa(Thread::Current());
- ProfilingInfoVisitor visitor(soa.Self(), chars.c_str());
- visitor.WalkStack();
+ ProcessMethodWithName(
+ env,
+ method_name,
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = stack_visitor->GetMethod();
+ ProfilingInfo::Create(Thread::Current(), m, /* retry_allocation */ true);
+ });
}
-class OsrCheckVisitor : public StackVisitor {
- public:
- OsrCheckVisitor(Thread* thread, const char* method_name)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- method_name_(method_name) {}
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtMethod* m = GetMethod();
- std::string m_name(m->GetName());
-
- jit::Jit* jit = Runtime::Current()->GetJit();
- if (m_name.compare(method_name_) == 0) {
- while (jit->GetCodeCache()->LookupOsrMethodHeader(m) == nullptr) {
- // Sleep to yield to the compiler thread.
- usleep(1000);
- // Will either ensure it's compiled or do the compilation itself.
- jit->CompileMethod(m, Thread::Current(), /* osr */ true);
- }
- return false;
- }
- return true;
- }
-
- const char* const method_name_;
-};
-
extern "C" JNIEXPORT void JNICALL Java_Main_ensureHasOsrCode(JNIEnv* env,
jclass,
jstring method_name) {
if (!Runtime::Current()->UseJitCompilation()) {
return;
}
- ScopedUtfChars chars(env, method_name);
- CHECK(chars.c_str() != nullptr);
- ScopedObjectAccess soa(Thread::Current());
- OsrCheckVisitor visitor(soa.Self(), chars.c_str());
- visitor.WalkStack();
+ ProcessMethodWithName(
+ env,
+ method_name,
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ArtMethod* m = stack_visitor->GetMethod();
+ jit::Jit* jit = Runtime::Current()->GetJit();
+ while (jit->GetCodeCache()->LookupOsrMethodHeader(m) == nullptr) {
+ // Sleep to yield to the compiler thread.
+ usleep(1000);
+ // Will either ensure it's compiled or do the compilation itself.
+ jit->CompileMethod(m, Thread::Current(), /* osr */ true);
+ }
+ });
}
} // namespace art
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index b0e0f07..28a737d 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -43,6 +43,10 @@
#define UNREACHABLE __builtin_unreachable
+// The tag value used on the Java side to tag the current thread.
+static constexpr jlong kThreadTag = 3000;
+static constexpr const char* kThreadReferree = "3000@0";
+
extern "C" JNIEXPORT void JNICALL Java_art_Test913_forceGarbageCollection(
JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
jvmtiError ret = jvmti_env->ForceGarbageCollection();
@@ -174,12 +178,12 @@
}
// Ignore classes (1000 <= tag < 3000) for thread objects. These can be held by the JIT.
if (reference_kind == JVMTI_HEAP_REFERENCE_THREAD && class_tag == 0 &&
- (1000 <= *tag_ptr && *tag_ptr < 3000)) {
+ (1000 <= *tag_ptr && *tag_ptr < kThreadTag)) {
return 0;
}
// Ignore stack-locals of untagged threads. That is the environment.
if (reference_kind == JVMTI_HEAP_REFERENCE_STACK_LOCAL &&
- reference_info->stack_local.thread_tag != 3000) {
+ reference_info->stack_local.thread_tag != kThreadTag) {
return 0;
}
// Ignore array elements with an untagged source. These are from the environment.
@@ -422,7 +426,7 @@
jint index = reference_info->array.index;
// Normalize if it's "0@0" -> "3000@1".
// TODO: A pre-pass could probably give us this index to check explicitly.
- if (referrer == "0@0" && referree == "3000@0") {
+ if (referrer == "0@0" && referree == kThreadReferree) {
index = 0;
}
std::string tmp = StringPrintf("array-element@%d", index);
@@ -645,7 +649,10 @@
const void* elements,
void* user_data) {
FindArrayCallbacks* p = reinterpret_cast<FindArrayCallbacks*>(user_data);
- if (*tag_ptr != 0) {
+ // The thread object may be reachable from the starting value because of setup in the
+ // framework (when this test runs as part of CTS). Ignore, we're not testing the thread
+ // here.)
+ if (*tag_ptr != 0 && *tag_ptr != kThreadTag) {
std::ostringstream oss;
oss << *tag_ptr
<< '@'
@@ -758,7 +765,10 @@
jvmtiPrimitiveType value_type,
void* user_data) {
FindFieldCallbacks* p = reinterpret_cast<FindFieldCallbacks*>(user_data);
- if (*tag_ptr != 0) {
+ // The thread object may be reachable from the starting value because of setup in the
+ // framework (when this test runs as part of CTS). Ignore, we're not testing the thread
+ // here.)
+ if (*tag_ptr != 0 && *tag_ptr != kThreadTag) {
std::ostringstream oss;
oss << *tag_ptr
<< '@'
diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc
index 581aa74..393e773 100644
--- a/test/common/stack_inspect.cc
+++ b/test/common/stack_inspect.cc
@@ -66,42 +66,30 @@
// public static native boolean isInterpretedFunction(String smali);
-// TODO Remove 'allow_runtime_frames' option once we have deoptimization through runtime frames.
-struct MethodIsInterpretedVisitor : public StackVisitor {
- public:
- MethodIsInterpretedVisitor(Thread* thread, ArtMethod* goal, bool require_deoptable)
- : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
- goal_(goal),
- method_is_interpreted_(true),
- method_found_(false),
- prev_was_runtime_(true),
- require_deoptable_(require_deoptable) {}
-
- bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
- if (goal_ == GetMethod()) {
- method_is_interpreted_ = (require_deoptable_ && prev_was_runtime_) || IsShadowFrame();
- method_found_ = true;
- return false;
- }
- prev_was_runtime_ = GetMethod()->IsRuntimeMethod();
- return true;
- }
-
- bool IsInterpreted() {
- return method_is_interpreted_;
- }
-
- bool IsFound() {
- return method_found_;
- }
-
- private:
- const ArtMethod* goal_;
- bool method_is_interpreted_;
- bool method_found_;
- bool prev_was_runtime_;
- bool require_deoptable_;
-};
+static bool IsMethodInterpreted(Thread* self,
+ const ArtMethod* goal,
+ const bool require_deoptable,
+ /* out */ bool* method_is_interpreted)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ *method_is_interpreted = true;
+ bool method_found = false;
+ bool prev_was_runtime = true;
+ StackVisitor::WalkStack(
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (goal == stack_visitor->GetMethod()) {
+ *method_is_interpreted =
+ (require_deoptable && prev_was_runtime) || stack_visitor->IsShadowFrame();
+ method_found = true;
+ return false;
+ }
+ prev_was_runtime = stack_visitor->GetMethod()->IsRuntimeMethod();
+ return true;
+ },
+ self,
+ /* context= */ nullptr,
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+ return method_found;
+}
// TODO Remove 'require_deoptimizable' option once we have deoptimization through runtime frames.
extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterpretedFunction(
@@ -119,23 +107,18 @@
env->ThrowNew(env->FindClass("java/lang/Error"), "Unable to interpret method argument!");
return JNI_FALSE;
}
- bool result;
- bool found;
{
ScopedObjectAccess soa(env);
ArtMethod* goal = jni::DecodeArtMethod(id);
- MethodIsInterpretedVisitor v(soa.Self(), goal, require_deoptimizable);
- v.WalkStack();
+ bool is_interpreted;
+ if (!IsMethodInterpreted(soa.Self(), goal, require_deoptimizable, &is_interpreted)) {
+ env->ThrowNew(env->FindClass("java/lang/Error"), "Unable to find given method in stack!");
+ return JNI_FALSE;
+ }
bool enters_interpreter = Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(
goal->GetEntryPointFromQuickCompiledCode());
- result = (v.IsInterpreted() || enters_interpreter);
- found = v.IsFound();
+ return (is_interpreted || enters_interpreter);
}
- if (!found) {
- env->ThrowNew(env->FindClass("java/lang/Error"), "Unable to find given method in stack!");
- return JNI_FALSE;
- }
- return result;
}
// public static native void assertIsInterpreted();
@@ -196,24 +179,24 @@
}
}
-struct GetCallingFrameVisitor : public StackVisitor {
- GetCallingFrameVisitor(Thread* thread, Context* context)
- REQUIRES_SHARED(Locks::mutator_lock_)
- : StackVisitor(thread, context, StackVisitor::StackWalkKind::kIncludeInlinedFrames) {}
-
- bool VisitFrame() override NO_THREAD_SAFETY_ANALYSIS {
- // Discard stubs and Main.getThisOfCaller.
- return GetMethod() == nullptr || GetMethod()->IsNative();
- }
-};
-
extern "C" JNIEXPORT jobject JNICALL Java_Main_getThisOfCaller(
JNIEnv* env, jclass cls ATTRIBUTE_UNUSED) {
ScopedObjectAccess soa(env);
std::unique_ptr<art::Context> context(art::Context::Create());
- GetCallingFrameVisitor visitor(soa.Self(), context.get());
- visitor.WalkStack();
- return soa.AddLocalReference<jobject>(visitor.GetThisObject());
+ jobject result = nullptr;
+ StackVisitor::WalkStack(
+ [&](const art::StackVisitor* stack_visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Discard stubs and Main.getThisOfCaller.
+ if (stack_visitor->GetMethod() == nullptr || stack_visitor->GetMethod()->IsNative()) {
+ return true;
+ }
+ result = soa.AddLocalReference<jobject>(stack_visitor->GetThisObject());
+ return false;
+ },
+ soa.Self(),
+ context.get(),
+ art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
+ return result;
}
} // namespace art
diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc
index 7f4c546..7c93a8b 100644
--- a/tools/hiddenapi/hiddenapi.cc
+++ b/tools/hiddenapi/hiddenapi.cc
@@ -1060,7 +1060,7 @@
// Write into public/private API files.
std::ofstream file_public(out_public_path_.c_str());
std::ofstream file_private(out_private_path_.c_str());
- for (const std::pair<std::string, bool> entry : boot_members) {
+ for (const std::pair<const std::string, bool>& entry : boot_members) {
if (entry.second) {
file_public << entry.first << std::endl;
} else {