summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/dex/verification_results.cc4
-rw-r--r--compiler/dex/verified_method.cc23
-rw-r--r--compiler/driver/compiler_driver.cc10
-rw-r--r--runtime/base/histogram-inl.h5
-rw-r--r--runtime/base/histogram.h1
-rw-r--r--runtime/debugger.cc6
-rw-r--r--runtime/gc/collector/garbage_collector.cc2
-rw-r--r--runtime/gc/heap.cc61
-rw-r--r--runtime/gc/heap.h13
-rw-r--r--runtime/jdwp/jdwp.h26
-rw-r--r--runtime/jdwp/jdwp_adb.cc6
-rw-r--r--runtime/jdwp/jdwp_event.cc694
-rw-r--r--runtime/jdwp/jdwp_expand_buf.cc4
-rw-r--r--runtime/jdwp/jdwp_handler.cc51
-rw-r--r--runtime/jdwp/jdwp_main.cc22
-rw-r--r--runtime/jdwp/jdwp_socket.cc10
-rw-r--r--runtime/jdwp/object_registry.cc4
-rw-r--r--runtime/mirror/art_method.h6
-rw-r--r--runtime/thread.cc5
-rw-r--r--runtime/thread_list.cc20
-rw-r--r--runtime/thread_list.h10
21 files changed, 471 insertions, 512 deletions
diff --git a/compiler/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 60d24068b1..4daed67784 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -57,8 +57,8 @@ bool VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method
const VerifiedMethod* verified_method = VerifiedMethod::Create(method_verifier, compile);
if (verified_method == nullptr) {
- DCHECK(method_verifier->HasFailures());
- return false;
+ // Do not report an error to the verifier. We'll just punt this later.
+ return true;
}
WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index d684bc9006..93e9a51da1 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -49,7 +49,6 @@ const VerifiedMethod* VerifiedMethod::Create(verifier::MethodVerifier* method_ve
if (compile) {
/* Generate a register map. */
if (!verified_method->GenerateGcMap(method_verifier)) {
- CHECK(method_verifier->HasFailures());
return nullptr; // Not a real failure, but a failure to encode.
}
if (kIsDebugBuild) {
@@ -83,17 +82,17 @@ bool VerifiedMethod::GenerateGcMap(verifier::MethodVerifier* method_verifier) {
ComputeGcMapSizes(method_verifier, &num_entries, &ref_bitmap_bits, &pc_bits);
// There's a single byte to encode the size of each bitmap.
if (ref_bitmap_bits >= kBitsPerByte * 8192 /* 13-bit size */) {
- // TODO: either a better GC map format or per method failures
- method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
- << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers";
+ LOG(WARNING) << "Cannot encode GC map for method with " << ref_bitmap_bits << " registers: "
+ << PrettyMethod(method_verifier->GetMethodReference().dex_method_index,
+ *method_verifier->GetMethodReference().dex_file);
return false;
}
size_t ref_bitmap_bytes = RoundUp(ref_bitmap_bits, kBitsPerByte) / kBitsPerByte;
// There are 2 bytes to encode the number of entries.
if (num_entries >= 65536) {
- // TODO: Either a better GC map format or per method failures.
- method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
- << "Cannot encode GC map for method with " << num_entries << " entries";
+ LOG(WARNING) << "Cannot encode GC map for method with " << num_entries << " entries: "
+ << PrettyMethod(method_verifier->GetMethodReference().dex_method_index,
+ *method_verifier->GetMethodReference().dex_file);
return false;
}
size_t pc_bytes;
@@ -105,10 +104,10 @@ bool VerifiedMethod::GenerateGcMap(verifier::MethodVerifier* method_verifier) {
format = verifier::kRegMapFormatCompact16;
pc_bytes = 2;
} else {
- // TODO: Either a better GC map format or per method failures.
- method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
- << "Cannot encode GC map for method with "
- << (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2)";
+ LOG(WARNING) << "Cannot encode GC map for method with "
+ << (1 << pc_bits) << " instructions (number is rounded up to nearest power of 2): "
+ << PrettyMethod(method_verifier->GetMethodReference().dex_method_index,
+ *method_verifier->GetMethodReference().dex_file);
return false;
}
size_t table_size = ((pc_bytes + ref_bitmap_bytes) * num_entries) + 4;
@@ -161,7 +160,7 @@ void VerifiedMethod::VerifyGcMap(verifier::MethodVerifier* method_verifier,
}
}
} else {
- DCHECK(reg_bitmap == NULL);
+ DCHECK(i >= 65536 || reg_bitmap == NULL);
}
}
}
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 051b310f89..cbb23c26b9 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2120,8 +2120,12 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
} else if ((access_flags & kAccAbstract) != 0) {
// Abstract methods don't have code.
} else {
+ bool has_verified_method = verification_results_->GetVerifiedMethod(method_ref) != nullptr;
bool compile = compilation_enabled &&
- verification_results_->IsCandidateForCompilation(method_ref, access_flags);
+ // Basic checks, e.g., not <clinit>.
+ verification_results_->IsCandidateForCompilation(method_ref, access_flags) &&
+ // Did not fail to create VerifiedMethod metadata.
+ has_verified_method;
if (compile) {
// NOTE: if compiler declines to compile this method, it will return nullptr.
compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx,
@@ -2129,10 +2133,12 @@ void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t
}
if (compiled_method == nullptr && dex_to_dex_compilation_level != kDontDexToDexCompile) {
// TODO: add a command-line option to disable DEX-to-DEX compilation ?
+ // Do not optimize if a VerifiedMethod is missing. SafeCast elision, for example, relies on
+ // it.
(*dex_to_dex_compiler_)(*this, code_item, access_flags,
invoke_type, class_def_idx,
method_idx, class_loader, dex_file,
- dex_to_dex_compilation_level);
+ has_verified_method ? dex_to_dex_compilation_level : kRequired);
}
}
if (kTimeCompileMethod) {
diff --git a/runtime/base/histogram-inl.h b/runtime/base/histogram-inl.h
index b329a31b1f..812ed86e40 100644
--- a/runtime/base/histogram-inl.h
+++ b/runtime/base/histogram-inl.h
@@ -35,10 +35,13 @@ template <class Value> inline void Histogram<Value>::AddValue(Value value) {
DCHECK_GT(new_max, max_);
GrowBuckets(new_max);
}
-
BucketiseValue(value);
}
+template <class Value> inline void Histogram<Value>::AdjustAndAddValue(Value value) {
+ AddValue(value / kAdjust);
+}
+
template <class Value> inline Histogram<Value>::Histogram(const char* name)
: kAdjust(0),
kInitialBucketCount(0),
diff --git a/runtime/base/histogram.h b/runtime/base/histogram.h
index 1e12be8c3e..78f6e1c7c7 100644
--- a/runtime/base/histogram.h
+++ b/runtime/base/histogram.h
@@ -46,6 +46,7 @@ template <class Value> class Histogram {
// This is the expected constructor when creating new Histograms.
Histogram(const char* name, Value initial_bucket_width, size_t max_buckets = 100);
void AddValue(Value);
+ void AdjustAndAddValue(Value); // Add a value after dividing it by kAdjust.
// Builds the cumulative distribution function from the frequency data.
// Accumulative summation of frequencies.
// cumulative_freq[i] = sum(frequency[j] : 0 < j < i )
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index a61b27109b..556f2f8726 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -669,9 +669,7 @@ void Dbg::StartJdwp() {
// This may cause us to suspend all threads.
if (gJdwpState->IsActive()) {
ScopedObjectAccess soa(Thread::Current());
- if (!gJdwpState->PostVMStart()) {
- LOG(WARNING) << "Failed to post 'start' message to debugger";
- }
+ gJdwpState->PostVMStart();
}
}
@@ -2569,7 +2567,7 @@ JDWP::JdwpError Dbg::GetLocalValues(JDWP::Request* request, JDWP::ExpandBuf* pRe
VLOG(jdwp) << " --> slot " << slot << " " << reqSigByte;
size_t width = Dbg::GetTagWidth(reqSigByte);
- uint8_t* ptr = expandBufAddSpace(pReply, width+1);
+ uint8_t* ptr = expandBufAddSpace(pReply, width + 1);
JDWP::JdwpError error = Dbg::GetLocalValue(visitor, soa, slot, reqSigByte, ptr, width);
if (error != JDWP::ERR_NONE) {
return error;
diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc
index 9e6a8003f4..8be18be676 100644
--- a/runtime/gc/collector/garbage_collector.cc
+++ b/runtime/gc/collector/garbage_collector.cc
@@ -102,7 +102,7 @@ void GarbageCollector::Run(GcCause gc_cause, bool clear_soft_references) {
total_time_ns_ += current_iteration->GetDurationNs();
for (uint64_t pause_time : current_iteration->GetPauseTimes()) {
MutexLock mu(self, pause_histogram_lock_);
- pause_histogram_.AddValue(pause_time / 1000);
+ pause_histogram_.AdjustAndAddValue(pause_time);
}
ATRACE_END();
}
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 0587bb5aba..8f09e074f7 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -143,6 +143,7 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
zygote_space_(nullptr),
large_object_threshold_(large_object_threshold),
gc_request_pending_(false),
+ conc_gc_running_(false),
collector_type_running_(kCollectorTypeNone),
last_gc_type_(collector::kGcTypeNone),
next_gc_type_(collector::kGcTypePartial),
@@ -167,8 +168,6 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
verify_pre_gc_rosalloc_(verify_pre_gc_rosalloc),
verify_pre_sweeping_rosalloc_(verify_pre_sweeping_rosalloc),
verify_post_gc_rosalloc_(verify_post_gc_rosalloc),
- last_gc_time_ns_(NanoTime()),
- allocation_rate_(0),
/* For GC a lot mode, we limit the allocations stacks to be kGcAlotInterval allocations. This
* causes a lot of GC since we do a GC for alloc whenever the stack is full. When heap
* verification is enabled, we limit the size of allocation stacks to speed up their
@@ -413,7 +412,6 @@ Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max
gc_request_lock_ = new Mutex("GC request lock");
gc_request_cond_.reset(new ConditionVariable("GC request condition variable", *gc_request_lock_));
heap_trim_request_lock_ = new Mutex("Heap trim request lock");
- last_gc_size_ = GetBytesAllocated();
if (ignore_max_footprint_) {
SetIdealFootprint(std::numeric_limits<size_t>::max());
concurrent_start_bytes_ = std::numeric_limits<size_t>::max();
@@ -859,7 +857,7 @@ void Heap::DumpGcPerformanceInfo(std::ostream& os) {
os << "Zygote space size " << PrettySize(zygote_space_->Size()) << "\n";
}
os << "Total mutator paused time: " << PrettyDuration(total_paused_time) << "\n";
- os << "Total time waiting for GC to complete: " << PrettyDuration(total_wait_time_) << "\n";
+ os << "Total time waiting for GC to complete: " << PrettyDuration(total_wait_time_);
BaseMutex::DumpAll(os);
}
@@ -2154,16 +2152,9 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCaus
++runtime->GetStats()->gc_for_alloc_count;
++self->GetStats()->gc_for_alloc_count;
}
- uint64_t gc_start_time_ns = NanoTime();
- uint64_t gc_start_size = GetBytesAllocated();
- // Approximate allocation rate in bytes / second.
- uint64_t ms_delta = NsToMs(gc_start_time_ns - last_gc_time_ns_);
- // Back to back GCs can cause 0 ms of wait time in between GC invocations.
- if (LIKELY(ms_delta != 0)) {
- allocation_rate_ = ((gc_start_size - last_gc_size_) * 1000) / ms_delta;
- ATRACE_INT("Allocation rate KB/s", allocation_rate_ / KB);
- VLOG(heap) << "Allocation rate: " << PrettySize(allocation_rate_) << "/s";
- }
+ const uint64_t bytes_allocated_before_gc = GetBytesAllocated();
+ // Approximate heap size.
+ ATRACE_INT("Heap size (KB)", bytes_allocated_before_gc / KB);
DCHECK_LT(gc_type, collector::kGcTypeMax);
DCHECK_NE(gc_type, collector::kGcTypeNone);
@@ -2220,7 +2211,7 @@ collector::GcType Heap::CollectGarbageInternal(collector::GcType gc_type, GcCaus
// Enqueue cleared references.
reference_processor_.EnqueueClearedReferences(self);
// Grow the heap so that we know when to perform the next GC.
- GrowForUtilization(collector);
+ GrowForUtilization(collector, bytes_allocated_before_gc);
const size_t duration = GetCurrentGcIteration()->GetDurationNs();
const std::vector<uint64_t>& pause_times = GetCurrentGcIteration()->GetPauseTimes();
// Print the GC if it is an explicit GC (e.g. Runtime.gc()) or a slow GC
@@ -2930,25 +2921,24 @@ double Heap::HeapGrowthMultiplier() const {
return foreground_heap_growth_multiplier_;
}
-void Heap::GrowForUtilization(collector::GarbageCollector* collector_ran) {
+void Heap::GrowForUtilization(collector::GarbageCollector* collector_ran,
+ uint64_t bytes_allocated_before_gc) {
// We know what our utilization is at this moment.
// This doesn't actually resize any memory. It just lets the heap grow more when necessary.
const uint64_t bytes_allocated = GetBytesAllocated();
- last_gc_size_ = bytes_allocated;
- last_gc_time_ns_ = NanoTime();
uint64_t target_size;
collector::GcType gc_type = collector_ran->GetGcType();
+ const double multiplier = HeapGrowthMultiplier(); // Use the multiplier to grow more for
+ // foreground.
+ const uint64_t adjusted_min_free = static_cast<uint64_t>(min_free_ * multiplier);
+ const uint64_t adjusted_max_free = static_cast<uint64_t>(max_free_ * multiplier);
if (gc_type != collector::kGcTypeSticky) {
// Grow the heap for non sticky GC.
- const float multiplier = HeapGrowthMultiplier(); // Use the multiplier to grow more for
- // foreground.
- intptr_t delta = bytes_allocated / GetTargetHeapUtilization() - bytes_allocated;
+ ssize_t delta = bytes_allocated / GetTargetHeapUtilization() - bytes_allocated;
CHECK_GE(delta, 0);
target_size = bytes_allocated + delta * multiplier;
- target_size = std::min(target_size,
- bytes_allocated + static_cast<uint64_t>(max_free_ * multiplier));
- target_size = std::max(target_size,
- bytes_allocated + static_cast<uint64_t>(min_free_ * multiplier));
+ target_size = std::min(target_size, bytes_allocated + adjusted_max_free);
+ target_size = std::max(target_size, bytes_allocated + adjusted_min_free);
native_need_to_run_finalization_ = true;
next_gc_type_ = collector::kGcTypeSticky;
} else {
@@ -2970,8 +2960,8 @@ void Heap::GrowForUtilization(collector::GarbageCollector* collector_ran) {
next_gc_type_ = non_sticky_gc_type;
}
// If we have freed enough memory, shrink the heap back down.
- if (bytes_allocated + max_free_ < max_allowed_footprint_) {
- target_size = bytes_allocated + max_free_;
+ if (bytes_allocated + adjusted_max_free < max_allowed_footprint_) {
+ target_size = bytes_allocated + adjusted_max_free;
} else {
target_size = std::max(bytes_allocated, static_cast<uint64_t>(max_allowed_footprint_));
}
@@ -2979,11 +2969,18 @@ void Heap::GrowForUtilization(collector::GarbageCollector* collector_ran) {
if (!ignore_max_footprint_) {
SetIdealFootprint(target_size);
if (IsGcConcurrent()) {
+ const uint64_t freed_bytes = current_gc_iteration_.GetFreedBytes() +
+ current_gc_iteration_.GetFreedLargeObjectBytes();
+ // Bytes allocated will shrink by freed_bytes after the GC runs, so if we want to figure out
+ // how many bytes were allocated during the GC we need to add freed_bytes back on.
+ CHECK_GE(bytes_allocated + freed_bytes, bytes_allocated_before_gc);
+ const uint64_t bytes_allocated_during_gc = bytes_allocated + freed_bytes -
+ bytes_allocated_before_gc;
// Calculate when to perform the next ConcurrentGC.
// Calculate the estimated GC duration.
const double gc_duration_seconds = NsToMs(current_gc_iteration_.GetDurationNs()) / 1000.0;
// Estimate how many remaining bytes we will have when we need to start the next GC.
- size_t remaining_bytes = allocation_rate_ * gc_duration_seconds;
+ size_t remaining_bytes = bytes_allocated_during_gc * gc_duration_seconds;
remaining_bytes = std::min(remaining_bytes, kMaxConcurrentRemainingBytes);
remaining_bytes = std::max(remaining_bytes, kMinConcurrentRemainingBytes);
if (UNLIKELY(remaining_bytes > max_allowed_footprint_)) {
@@ -3278,17 +3275,21 @@ void Heap::ClearMarkedObjects() {
void Heap::WaitForConcurrentGCRequest(Thread* self) {
ScopedThreadStateChange tsc(self, kBlocked);
MutexLock mu(self, *gc_request_lock_);
+ conc_gc_running_ = false;
while (!gc_request_pending_) {
gc_request_cond_->Wait(self);
}
gc_request_pending_ = false;
+ conc_gc_running_ = true;
}
void Heap::NotifyConcurrentGCRequest(Thread* self) {
ScopedThreadStateChange tsc(self, kBlocked);
MutexLock mu(self, *gc_request_lock_);
- gc_request_pending_ = true;
- gc_request_cond_->Signal(self);
+ if (!conc_gc_running_) {
+ gc_request_pending_ = true;
+ gc_request_cond_->Signal(self);
+ }
}
} // namespace gc
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 529af9539e..cf94eb6a9d 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -755,8 +755,10 @@ class Heap {
// Given the current contents of the alloc space, increase the allowed heap footprint to match
// the target utilization ratio. This should only be called immediately after a full garbage
- // collection.
- void GrowForUtilization(collector::GarbageCollector* collector_ran);
+ // collection. bytes_allocated_before_gc is used to measure bytes / second for the period which
+ // the GC was run.
+ void GrowForUtilization(collector::GarbageCollector* collector_ran,
+ uint64_t bytes_allocated_before_gc = 0);
size_t GetPercentFree();
@@ -881,6 +883,7 @@ class Heap {
Mutex* gc_request_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
std::unique_ptr<ConditionVariable> gc_request_cond_ GUARDED_BY(gc_request_lock_);
bool gc_request_pending_ GUARDED_BY(gc_request_lock_);
+ bool conc_gc_running_ GUARDED_BY(gc_request_lock_);
// Reference processor;
ReferenceProcessor reference_processor_;
@@ -971,12 +974,6 @@ class Heap {
// Parallel GC data structures.
std::unique_ptr<ThreadPool> thread_pool_;
- // The nanosecond time at which the last GC ended.
- uint64_t last_gc_time_ns_;
-
- // How many bytes were allocated at the end of the last GC.
- uint64_t last_gc_size_;
-
// Estimated allocation rate (bytes / second). Computed between the time of the last GC cycle
// and the start of the current one.
uint64_t allocation_rate_;
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index 0c9451ceeb..aa0c103a9b 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -27,6 +27,7 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
+#include <vector>
struct iovec;
@@ -188,7 +189,7 @@ struct JdwpState {
* The VM has finished initializing. Only called when the debugger is
* connected at the time initialization completes.
*/
- bool PostVMStart() LOCKS_EXCLUDED(event_list_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void PostVMStart() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
* A location of interest has been reached. This is used for breakpoints,
@@ -202,7 +203,7 @@ struct JdwpState {
*
* "returnValue" is non-null for MethodExit events only.
*/
- bool PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr, int eventFlags,
+ void PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr, int eventFlags,
const JValue* returnValue)
LOCKS_EXCLUDED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -214,7 +215,7 @@ struct JdwpState {
* "fieldValue" is non-null for field modification events only.
* "is_modification" is true for field modification, false for field access.
*/
- bool PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field, mirror::Object* thisPtr,
+ void PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field, mirror::Object* thisPtr,
const JValue* fieldValue, bool is_modification)
LOCKS_EXCLUDED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -224,7 +225,7 @@ struct JdwpState {
*
* Pass in a zeroed-out "*pCatchLoc" if the exception wasn't caught.
*/
- bool PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object,
+ void PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object,
const EventLocation* pCatchLoc, mirror::Object* thisPtr)
LOCKS_EXCLUDED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -232,14 +233,14 @@ struct JdwpState {
/*
* A thread has started or stopped.
*/
- bool PostThreadChange(Thread* thread, bool start)
+ void PostThreadChange(Thread* thread, bool start)
LOCKS_EXCLUDED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
/*
* Class has been prepared.
*/
- bool PostClassPrepare(mirror::Class* klass)
+ void PostClassPrepare(mirror::Class* klass)
LOCKS_EXCLUDED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -307,15 +308,16 @@ struct JdwpState {
void SendRequestAndPossiblySuspend(ExpandBuf* pReq, JdwpSuspendPolicy suspend_policy,
ObjectId threadId)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CleanupMatchList(JdwpEvent** match_list,
- size_t match_count)
+ void CleanupMatchList(const std::vector<JdwpEvent*>& match_list)
EXCLUSIVE_LOCKS_REQUIRED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void EventFinish(ExpandBuf* pReq);
- void FindMatchingEvents(JdwpEventKind eventKind,
- const ModBasket& basket,
- JdwpEvent** match_list,
- size_t* pMatchCount)
+ bool FindMatchingEvents(JdwpEventKind eventKind, const ModBasket& basket,
+ std::vector<JdwpEvent*>* match_list)
+ LOCKS_EXCLUDED(event_list_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void FindMatchingEventsLocked(JdwpEventKind eventKind, const ModBasket& basket,
+ std::vector<JdwpEvent*>* match_list)
EXCLUSIVE_LOCKS_REQUIRED(event_list_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void UnregisterEvent(JdwpEvent* pEvent)
diff --git a/runtime/jdwp/jdwp_adb.cc b/runtime/jdwp/jdwp_adb.cc
index df7d068922..adc2912e58 100644
--- a/runtime/jdwp/jdwp_adb.cc
+++ b/runtime/jdwp/jdwp_adb.cc
@@ -123,7 +123,7 @@ struct JdwpAdbState : public JdwpNetStateBase {
bool InitAdbTransport(JdwpState* state, const JdwpOptions*) {
VLOG(jdwp) << "ADB transport startup";
state->netState = new JdwpAdbState(state);
- return (state->netState != NULL);
+ return (state->netState != nullptr);
}
/*
@@ -145,7 +145,7 @@ int JdwpAdbState::ReceiveClientFd() {
iov.iov_len = 1;
msghdr msg;
- msg.msg_name = NULL;
+ msg.msg_name = nullptr;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
@@ -352,7 +352,7 @@ bool JdwpAdbState::ProcessIncoming() {
* re-issue the select. We're currently using #2, as it's more
* reliable than #1 and generally better than #3. Wastes two fds.
*/
- selCount = select(maxfd+1, &readfds, NULL, NULL, NULL);
+ selCount = select(maxfd + 1, &readfds, nullptr, nullptr, nullptr);
if (selCount < 0) {
if (errno == EINTR) {
continue;
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index 1e0a2d2c22..1bf16b285c 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -172,9 +172,9 @@ static uint32_t GetInstrumentationEventFor(JdwpEventKind eventKind) {
* not be added to the list, and an appropriate error will be returned.
*/
JdwpError JdwpState::RegisterEvent(JdwpEvent* pEvent) {
- CHECK(pEvent != NULL);
- CHECK(pEvent->prev == NULL);
- CHECK(pEvent->next == NULL);
+ CHECK(pEvent != nullptr);
+ CHECK(pEvent->prev == nullptr);
+ CHECK(pEvent->next == nullptr);
{
/*
@@ -223,7 +223,7 @@ JdwpError JdwpState::RegisterEvent(JdwpEvent* pEvent) {
* Add to list.
*/
MutexLock mu(Thread::Current(), event_list_lock_);
- if (event_list_ != NULL) {
+ if (event_list_ != nullptr) {
pEvent->next = event_list_;
event_list_->prev = pEvent;
}
@@ -245,7 +245,7 @@ JdwpError JdwpState::RegisterEvent(JdwpEvent* pEvent) {
* Grab the eventLock before calling here.
*/
void JdwpState::UnregisterEvent(JdwpEvent* pEvent) {
- if (pEvent->prev == NULL) {
+ if (pEvent->prev == nullptr) {
/* head of the list */
CHECK(event_list_ == pEvent);
@@ -254,11 +254,11 @@ void JdwpState::UnregisterEvent(JdwpEvent* pEvent) {
pEvent->prev->next = pEvent->next;
}
- if (pEvent->next != NULL) {
+ if (pEvent->next != nullptr) {
pEvent->next->prev = pEvent->prev;
- pEvent->next = NULL;
+ pEvent->next = nullptr;
}
- pEvent->prev = NULL;
+ pEvent->prev = nullptr;
{
/*
@@ -303,7 +303,7 @@ void JdwpState::UnregisterEvent(JdwpEvent* pEvent) {
}
--event_list_size_;
- CHECK(event_list_size_ != 0 || event_list_ == NULL);
+ CHECK(event_list_size_ != 0 || event_list_ == nullptr);
}
/*
@@ -343,7 +343,7 @@ void JdwpState::UnregisterAll() {
MutexLock mu(Thread::Current(), event_list_lock_);
JdwpEvent* pEvent = event_list_;
- while (pEvent != NULL) {
+ while (pEvent != nullptr) {
JdwpEvent* pNextEvent = pEvent->next;
UnregisterEvent(pEvent);
@@ -351,7 +351,7 @@ void JdwpState::UnregisterAll() {
pEvent = pNextEvent;
}
- event_list_ = NULL;
+ event_list_ = nullptr;
}
/*
@@ -372,13 +372,13 @@ JdwpEvent* EventAlloc(int numMods) {
* Do not call this until the event has been removed from the list.
*/
void EventFree(JdwpEvent* pEvent) {
- if (pEvent == NULL) {
+ if (pEvent == nullptr) {
return;
}
/* make sure it was removed from the list */
- CHECK(pEvent->prev == NULL);
- CHECK(pEvent->next == NULL);
+ CHECK(pEvent->prev == nullptr);
+ CHECK(pEvent->next == nullptr);
/* want to check state->event_list_ != pEvent */
/*
@@ -387,11 +387,11 @@ void EventFree(JdwpEvent* pEvent) {
for (int i = 0; i < pEvent->modCount; i++) {
if (pEvent->mods[i].modKind == MK_CLASS_MATCH) {
free(pEvent->mods[i].classMatch.classPattern);
- pEvent->mods[i].classMatch.classPattern = NULL;
+ pEvent->mods[i].classMatch.classPattern = nullptr;
}
if (pEvent->mods[i].modKind == MK_CLASS_EXCLUDE) {
free(pEvent->mods[i].classExclude.classPattern);
- pEvent->mods[i].classExclude.classPattern = NULL;
+ pEvent->mods[i].classExclude.classPattern = nullptr;
}
}
@@ -399,26 +399,12 @@ void EventFree(JdwpEvent* pEvent) {
}
/*
- * Allocate storage for matching events. To keep things simple we
- * use an array with enough storage for the entire list.
- *
- * The state->eventLock should be held before calling.
- */
-static JdwpEvent** AllocMatchList(size_t event_count) {
- return new JdwpEvent*[event_count];
-}
-
-/*
* Run through the list and remove any entries with an expired "count" mod
- * from the event list, then free the match list.
+ * from the event list.
*/
-void JdwpState::CleanupMatchList(JdwpEvent** match_list, size_t match_count) {
- JdwpEvent** ppEvent = match_list;
-
- while (match_count--) {
- JdwpEvent* pEvent = *ppEvent;
-
- for (int i = 0; i < pEvent->modCount; i++) {
+void JdwpState::CleanupMatchList(const std::vector<JdwpEvent*>& match_list) {
+ for (JdwpEvent* pEvent : match_list) {
+ for (int i = 0; i < pEvent->modCount; ++i) {
if (pEvent->mods[i].modKind == MK_COUNT && pEvent->mods[i].count.count == 0) {
VLOG(jdwp) << StringPrintf("##### Removing expired event (requestId=%#" PRIx32 ")",
pEvent->requestId);
@@ -427,11 +413,7 @@ void JdwpState::CleanupMatchList(JdwpEvent** match_list, size_t match_count) {
break;
}
}
-
- ppEvent++;
}
-
- delete[] match_list;
}
/*
@@ -536,40 +518,55 @@ static bool ModsMatch(JdwpEvent* pEvent, const ModBasket& basket)
}
/*
- * Find all events of type "eventKind" with mods that match up with the
- * rest of the arguments.
+ * Find all events of type "event_kind" with mods that match up with the
+ * rest of the arguments while holding the event list lock. This method
+ * is used by FindMatchingEvents below.
*
- * Found events are appended to "match_list", and "*pMatchCount" is advanced,
- * so this may be called multiple times for grouped events.
+ * Found events are appended to "match_list" so this may be called multiple times for grouped
+ * events.
*
* DO NOT call this multiple times for the same eventKind, as Count mods are
* decremented during the scan.
*/
-void JdwpState::FindMatchingEvents(JdwpEventKind eventKind, const ModBasket& basket,
- JdwpEvent** match_list, size_t* pMatchCount) {
- /* start after the existing entries */
- match_list += *pMatchCount;
-
+void JdwpState::FindMatchingEventsLocked(JdwpEventKind event_kind, const ModBasket& basket,
+ std::vector<JdwpEvent*>* match_list) {
for (JdwpEvent* pEvent = event_list_; pEvent != nullptr; pEvent = pEvent->next) {
- if (pEvent->eventKind == eventKind && ModsMatch(pEvent, basket)) {
- *match_list++ = pEvent;
- (*pMatchCount)++;
+ if (pEvent->eventKind == event_kind && ModsMatch(pEvent, basket)) {
+ match_list->push_back(pEvent);
}
}
}
/*
+ * Find all events of type "event_kind" with mods that match up with the
+ * rest of the arguments and return true if at least one event matches,
+ * false otherwise.
+ *
+ * Found events are appended to "match_list" so this may be called multiple
+ * times for grouped events.
+ *
+ * DO NOT call this multiple times for the same eventKind, as Count mods are
+ * decremented during the scan.
+ */
+bool JdwpState::FindMatchingEvents(JdwpEventKind event_kind, const ModBasket& basket,
+ std::vector<JdwpEvent*>* match_list) {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ match_list->reserve(event_list_size_);
+ FindMatchingEventsLocked(event_kind, basket, match_list);
+ return !match_list->empty();
+}
+
+/*
* Scan through the list of matches and determine the most severe
* suspension policy.
*/
-static JdwpSuspendPolicy scanSuspendPolicy(JdwpEvent** match_list, int match_count) {
+static JdwpSuspendPolicy ScanSuspendPolicy(const std::vector<JdwpEvent*>& match_list) {
JdwpSuspendPolicy policy = SP_NONE;
- while (match_count--) {
- if ((*match_list)->suspend_policy > policy) {
- policy = (*match_list)->suspend_policy;
+ for (JdwpEvent* pEvent : match_list) {
+ if (pEvent->suspend_policy > policy) {
+ policy = pEvent->suspend_policy;
}
- match_list++;
}
return policy;
@@ -626,19 +623,18 @@ void JdwpState::SuspendByPolicy(JdwpSuspendPolicy suspend_policy, JDWP::ObjectId
void JdwpState::SendRequestAndPossiblySuspend(ExpandBuf* pReq, JdwpSuspendPolicy suspend_policy,
ObjectId threadId) {
- Thread* self = Thread::Current();
+ Thread* const self = Thread::Current();
self->AssertThreadSuspensionIsAllowable();
+ CHECK(pReq != nullptr);
/* send request and possibly suspend ourselves */
- if (pReq != NULL) {
- JDWP::ObjectId thread_self_id = Dbg::GetThreadSelfId();
- self->TransitionFromRunnableToSuspended(kWaitingForDebuggerSend);
- if (suspend_policy != SP_NONE) {
- SetWaitForEventThread(threadId);
- }
- EventFinish(pReq);
- SuspendByPolicy(suspend_policy, thread_self_id);
- self->TransitionFromSuspendedToRunnable();
+ JDWP::ObjectId thread_self_id = Dbg::GetThreadSelfId();
+ self->TransitionFromRunnableToSuspended(kWaitingForDebuggerSend);
+ if (suspend_policy != SP_NONE) {
+ SetWaitForEventThread(threadId);
}
+ EventFinish(pReq);
+ SuspendByPolicy(suspend_policy, thread_self_id);
+ self->TransitionFromSuspendedToRunnable();
}
/*
@@ -729,10 +725,10 @@ void JdwpState::EventFinish(ExpandBuf* pReq) {
uint8_t* buf = expandBufGetBuffer(pReq);
Set4BE(buf, expandBufGetLength(pReq));
- Set4BE(buf+4, NextRequestSerial());
- Set1(buf+8, 0); /* flags */
- Set1(buf+9, kJdwpEventCommandSet);
- Set1(buf+10, kJdwpCompositeCommand);
+ Set4BE(buf + 4, NextRequestSerial());
+ Set1(buf + 8, 0); /* flags */
+ Set1(buf + 9, kJdwpEventCommandSet);
+ Set1(buf + 10, kJdwpCompositeCommand);
// Prevents from interleaving commands and events. Otherwise we could end up in sending an event
// before sending the reply of the command being processed and would lead to bad synchronization
@@ -753,43 +749,30 @@ void JdwpState::EventFinish(ExpandBuf* pReq) {
* any application code has been executed". The thread ID in the message
* must be for the main thread.
*/
-bool JdwpState::PostVMStart() {
- JdwpSuspendPolicy suspend_policy;
+void JdwpState::PostVMStart() {
+ JdwpSuspendPolicy suspend_policy = (options_->suspend) ? SP_ALL : SP_NONE;
ObjectId threadId = Dbg::GetThreadSelfId();
- if (options_->suspend) {
- suspend_policy = SP_ALL;
- } else {
- suspend_policy = SP_NONE;
- }
+ VLOG(jdwp) << "EVENT: " << EK_VM_START;
+ VLOG(jdwp) << " suspend_policy=" << suspend_policy;
ExpandBuf* pReq = eventPrep();
- {
- MutexLock mu(Thread::Current(), event_list_lock_); // probably don't need this here
-
- VLOG(jdwp) << "EVENT: " << EK_VM_START;
- VLOG(jdwp) << " suspend_policy=" << suspend_policy;
-
- expandBufAdd1(pReq, suspend_policy);
- expandBufAdd4BE(pReq, 1);
-
- expandBufAdd1(pReq, EK_VM_START);
- expandBufAdd4BE(pReq, 0); /* requestId */
- expandBufAdd8BE(pReq, threadId);
- }
+ expandBufAdd1(pReq, suspend_policy);
+ expandBufAdd4BE(pReq, 1);
+ expandBufAdd1(pReq, EK_VM_START);
+ expandBufAdd4BE(pReq, 0); /* requestId */
+ expandBufAddObjectId(pReq, threadId);
Dbg::ManageDeoptimization();
/* send request and possibly suspend ourselves */
SendRequestAndPossiblySuspend(pReq, suspend_policy, threadId);
-
- return true;
}
-static void LogMatchingEventsAndThread(JdwpEvent** match_list, size_t match_count,
+static void LogMatchingEventsAndThread(const std::vector<JdwpEvent*> match_list,
ObjectId thread_id)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- for (size_t i = 0; i < match_count; ++i) {
+ for (size_t i = 0, e = match_list.size(); i < e; ++i) {
JdwpEvent* pEvent = match_list[i];
VLOG(jdwp) << "EVENT #" << i << ": " << pEvent->eventKind
<< StringPrintf(" (requestId=%#" PRIx32 ")", pEvent->requestId);
@@ -831,7 +814,7 @@ static void SetJdwpLocationFromEventLocation(const JDWP::EventLocation* event_lo
* - Single-step to a line with a breakpoint. Should get a single
* event message with both events in it.
*/
-bool JdwpState::PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr,
+void JdwpState::PostLocationEvent(const EventLocation* pLoc, mirror::Object* thisPtr,
int eventFlags, const JValue* returnValue) {
DCHECK(pLoc != nullptr);
DCHECK(pLoc->method != nullptr);
@@ -852,7 +835,7 @@ bool JdwpState::PostLocationEvent(const EventLocation* pLoc, mirror::Object* thi
*/
if (basket.thread == GetDebugThread()) {
VLOG(jdwp) << "Ignoring location event in JDWP thread";
- return false;
+ return;
}
/*
@@ -866,73 +849,69 @@ bool JdwpState::PostLocationEvent(const EventLocation* pLoc, mirror::Object* thi
*/
if (InvokeInProgress()) {
VLOG(jdwp) << "Not checking breakpoints during invoke (" << basket.className << ")";
- return false;
+ return;
}
- size_t match_count = 0;
- ExpandBuf* pReq = NULL;
- JdwpSuspendPolicy suspend_policy = SP_NONE;
- JdwpEvent** match_list = nullptr;
- ObjectId thread_id = 0;
+ std::vector<JdwpEvent*> match_list;
{
- {
- MutexLock mu(Thread::Current(), event_list_lock_);
- match_list = AllocMatchList(event_list_size_);
- if ((eventFlags & Dbg::kBreakpoint) != 0) {
- FindMatchingEvents(EK_BREAKPOINT, basket, match_list, &match_count);
- }
- if ((eventFlags & Dbg::kSingleStep) != 0) {
- FindMatchingEvents(EK_SINGLE_STEP, basket, match_list, &match_count);
- }
- if ((eventFlags & Dbg::kMethodEntry) != 0) {
- FindMatchingEvents(EK_METHOD_ENTRY, basket, match_list, &match_count);
- }
- if ((eventFlags & Dbg::kMethodExit) != 0) {
- FindMatchingEvents(EK_METHOD_EXIT, basket, match_list, &match_count);
- FindMatchingEvents(EK_METHOD_EXIT_WITH_RETURN_VALUE, basket, match_list, &match_count);
- }
+ // We use the locked version because we have multiple possible match events.
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ match_list.reserve(event_list_size_);
+ if ((eventFlags & Dbg::kBreakpoint) != 0) {
+ FindMatchingEventsLocked(EK_BREAKPOINT, basket, &match_list);
}
- if (match_count != 0) {
- suspend_policy = scanSuspendPolicy(match_list, match_count);
+ if ((eventFlags & Dbg::kSingleStep) != 0) {
+ FindMatchingEventsLocked(EK_SINGLE_STEP, basket, &match_list);
+ }
+ if ((eventFlags & Dbg::kMethodEntry) != 0) {
+ FindMatchingEventsLocked(EK_METHOD_ENTRY, basket, &match_list);
+ }
+ if ((eventFlags & Dbg::kMethodExit) != 0) {
+ FindMatchingEventsLocked(EK_METHOD_EXIT, basket, &match_list);
+ FindMatchingEventsLocked(EK_METHOD_EXIT_WITH_RETURN_VALUE, basket, &match_list);
+ }
+ }
+ if (match_list.empty()) {
+ // No matching event.
+ return;
+ }
+ JdwpSuspendPolicy suspend_policy = ScanSuspendPolicy(match_list);
- thread_id = Dbg::GetThreadId(basket.thread);
- JDWP::JdwpLocation jdwp_location;
- SetJdwpLocationFromEventLocation(pLoc, &jdwp_location);
+ ObjectId thread_id = Dbg::GetThreadId(basket.thread);
+ JDWP::JdwpLocation jdwp_location;
+ SetJdwpLocationFromEventLocation(pLoc, &jdwp_location);
- if (VLOG_IS_ON(jdwp)) {
- LogMatchingEventsAndThread(match_list, match_count, thread_id);
- VLOG(jdwp) << " location=" << jdwp_location;
- VLOG(jdwp) << " suspend_policy=" << suspend_policy;
- }
+ if (VLOG_IS_ON(jdwp)) {
+ LogMatchingEventsAndThread(match_list, thread_id);
+ VLOG(jdwp) << " location=" << jdwp_location;
+ VLOG(jdwp) << " suspend_policy=" << suspend_policy;
+ }
- pReq = eventPrep();
- expandBufAdd1(pReq, suspend_policy);
- expandBufAdd4BE(pReq, match_count);
-
- for (size_t i = 0; i < match_count; i++) {
- expandBufAdd1(pReq, match_list[i]->eventKind);
- expandBufAdd4BE(pReq, match_list[i]->requestId);
- expandBufAdd8BE(pReq, thread_id);
- expandBufAddLocation(pReq, jdwp_location);
- if (match_list[i]->eventKind == EK_METHOD_EXIT_WITH_RETURN_VALUE) {
- Dbg::OutputMethodReturnValue(jdwp_location.method_id, returnValue, pReq);
- }
- }
+ ExpandBuf* pReq = eventPrep();
+ expandBufAdd1(pReq, suspend_policy);
+ expandBufAdd4BE(pReq, match_list.size());
+
+ for (const JdwpEvent* pEvent : match_list) {
+ expandBufAdd1(pReq, pEvent->eventKind);
+ expandBufAdd4BE(pReq, pEvent->requestId);
+ expandBufAddObjectId(pReq, thread_id);
+ expandBufAddLocation(pReq, jdwp_location);
+ if (pEvent->eventKind == EK_METHOD_EXIT_WITH_RETURN_VALUE) {
+ Dbg::OutputMethodReturnValue(jdwp_location.method_id, returnValue, pReq);
}
+ }
- {
- MutexLock mu(Thread::Current(), event_list_lock_);
- CleanupMatchList(match_list, match_count);
- }
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ CleanupMatchList(match_list);
}
Dbg::ManageDeoptimization();
SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
- return match_count != 0;
}
-bool JdwpState::PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field,
+void JdwpState::PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* field,
mirror::Object* this_object, const JValue* fieldValue,
bool is_modification) {
DCHECK(pLoc != nullptr);
@@ -950,86 +929,73 @@ bool JdwpState::PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* fiel
if (InvokeInProgress()) {
VLOG(jdwp) << "Not posting field event during invoke";
- return false;
+ return;
}
- size_t match_count = 0;
- ExpandBuf* pReq = NULL;
- JdwpSuspendPolicy suspend_policy = SP_NONE;
- JdwpEvent** match_list = nullptr;
- ObjectId thread_id = 0;
- {
- {
- MutexLock mu(Thread::Current(), event_list_lock_);
- match_list = AllocMatchList(event_list_size_);
- if (is_modification) {
- FindMatchingEvents(EK_FIELD_MODIFICATION, basket, match_list, &match_count);
- } else {
- FindMatchingEvents(EK_FIELD_ACCESS, basket, match_list, &match_count);
- }
- }
- if (match_count != 0) {
- suspend_policy = scanSuspendPolicy(match_list, match_count);
-
- thread_id = Dbg::GetThreadId(basket.thread);
- ObjectRegistry* registry = Dbg::GetObjectRegistry();
- ObjectId instance_id = registry->Add(basket.thisPtr);
- RefTypeId field_type_id = registry->AddRefType(field->GetDeclaringClass());
- FieldId field_id = Dbg::ToFieldId(field);
- JDWP::JdwpLocation jdwp_location;
- SetJdwpLocationFromEventLocation(pLoc, &jdwp_location);
-
- if (VLOG_IS_ON(jdwp)) {
- LogMatchingEventsAndThread(match_list, match_count, thread_id);
- VLOG(jdwp) << " location=" << jdwp_location;
- VLOG(jdwp) << StringPrintf(" this=%#" PRIx64, instance_id);
- VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, field_type_id) << " "
- << Dbg::GetClassName(field_id);
- VLOG(jdwp) << StringPrintf(" field=%#" PRIx32, field_id) << " "
- << Dbg::GetFieldName(field_id);
- VLOG(jdwp) << " suspend_policy=" << suspend_policy;
- }
+ std::vector<JdwpEvent*> match_list;
+ const JdwpEventKind match_kind = (is_modification) ? EK_FIELD_MODIFICATION : EK_FIELD_ACCESS;
+ if (!FindMatchingEvents(match_kind, basket, &match_list)) {
+ // No matching event.
+ return;
+ }
- pReq = eventPrep();
- expandBufAdd1(pReq, suspend_policy);
- expandBufAdd4BE(pReq, match_count);
+ JdwpSuspendPolicy suspend_policy = ScanSuspendPolicy(match_list);
+ ObjectId thread_id = Dbg::GetThreadId(basket.thread);
+ ObjectRegistry* registry = Dbg::GetObjectRegistry();
+ ObjectId instance_id = registry->Add(basket.thisPtr);
+ RefTypeId field_type_id = registry->AddRefType(field->GetDeclaringClass());
+ FieldId field_id = Dbg::ToFieldId(field);
+ JDWP::JdwpLocation jdwp_location;
+ SetJdwpLocationFromEventLocation(pLoc, &jdwp_location);
+
+ if (VLOG_IS_ON(jdwp)) {
+ LogMatchingEventsAndThread(match_list, thread_id);
+ VLOG(jdwp) << " location=" << jdwp_location;
+ VLOG(jdwp) << StringPrintf(" this=%#" PRIx64, instance_id);
+ VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, field_type_id) << " "
+ << Dbg::GetClassName(field_id);
+ VLOG(jdwp) << StringPrintf(" field=%#" PRIx32, field_id) << " "
+ << Dbg::GetFieldName(field_id);
+ VLOG(jdwp) << " suspend_policy=" << suspend_policy;
+ }
- // Get field's reference type tag.
- JDWP::JdwpTypeTag type_tag = Dbg::GetTypeTag(field->GetDeclaringClass());
+ ExpandBuf* pReq = eventPrep();
+ expandBufAdd1(pReq, suspend_policy);
+ expandBufAdd4BE(pReq, match_list.size());
- // Get instance type tag.
- uint8_t tag;
- {
- ScopedObjectAccessUnchecked soa(Thread::Current());
- tag = Dbg::TagFromObject(soa, basket.thisPtr);
- }
+ // Get field's reference type tag.
+ JDWP::JdwpTypeTag type_tag = Dbg::GetTypeTag(field->GetDeclaringClass());
- for (size_t i = 0; i < match_count; i++) {
- expandBufAdd1(pReq, match_list[i]->eventKind);
- expandBufAdd4BE(pReq, match_list[i]->requestId);
- expandBufAdd8BE(pReq, thread_id);
- expandBufAddLocation(pReq, jdwp_location);
- expandBufAdd1(pReq, type_tag);
- expandBufAddRefTypeId(pReq, field_type_id);
- expandBufAddFieldId(pReq, field_id);
- expandBufAdd1(pReq, tag);
- expandBufAddObjectId(pReq, instance_id);
- if (is_modification) {
- Dbg::OutputFieldValue(field_id, fieldValue, pReq);
- }
- }
- }
+ // Get instance type tag.
+ uint8_t tag;
+ {
+ ScopedObjectAccessUnchecked soa(Thread::Current());
+ tag = Dbg::TagFromObject(soa, basket.thisPtr);
+ }
- {
- MutexLock mu(Thread::Current(), event_list_lock_);
- CleanupMatchList(match_list, match_count);
+ for (const JdwpEvent* pEvent : match_list) {
+ expandBufAdd1(pReq, pEvent->eventKind);
+ expandBufAdd4BE(pReq, pEvent->requestId);
+ expandBufAddObjectId(pReq, thread_id);
+ expandBufAddLocation(pReq, jdwp_location);
+ expandBufAdd1(pReq, type_tag);
+ expandBufAddRefTypeId(pReq, field_type_id);
+ expandBufAddFieldId(pReq, field_id);
+ expandBufAdd1(pReq, tag);
+ expandBufAddObjectId(pReq, instance_id);
+ if (is_modification) {
+ Dbg::OutputFieldValue(field_id, fieldValue, pReq);
}
}
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ CleanupMatchList(match_list);
+ }
+
Dbg::ManageDeoptimization();
SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
- return match_count != 0;
}
/*
@@ -1038,7 +1004,7 @@ bool JdwpState::PostFieldEvent(const EventLocation* pLoc, mirror::ArtField* fiel
* Valid mods:
* Count, ThreadOnly
*/
-bool JdwpState::PostThreadChange(Thread* thread, bool start) {
+void JdwpState::PostThreadChange(Thread* thread, bool start) {
CHECK_EQ(thread, Thread::Current());
/*
@@ -1046,61 +1012,45 @@ bool JdwpState::PostThreadChange(Thread* thread, bool start) {
*/
if (InvokeInProgress()) {
LOG(WARNING) << "Not posting thread change during invoke";
- return false;
+ return;
}
ModBasket basket;
basket.thread = thread;
- ExpandBuf* pReq = NULL;
- JdwpSuspendPolicy suspend_policy = SP_NONE;
- JdwpEvent** match_list = nullptr;
- size_t match_count = 0;
- ObjectId thread_id = 0;
- {
- {
- // Don't allow the list to be updated while we scan it.
- MutexLock mu(Thread::Current(), event_list_lock_);
- match_list = AllocMatchList(event_list_size_);
- if (start) {
- FindMatchingEvents(EK_THREAD_START, basket, match_list, &match_count);
- } else {
- FindMatchingEvents(EK_THREAD_DEATH, basket, match_list, &match_count);
- }
- }
-
- if (match_count != 0) {
- suspend_policy = scanSuspendPolicy(match_list, match_count);
+ std::vector<JdwpEvent*> match_list;
+ const JdwpEventKind match_kind = (start) ? EK_THREAD_START : EK_THREAD_DEATH;
+ if (!FindMatchingEvents(match_kind, basket, &match_list)) {
+ // No matching event.
+ return;
+ }
- thread_id = Dbg::GetThreadId(basket.thread);
+ JdwpSuspendPolicy suspend_policy = ScanSuspendPolicy(match_list);
+ ObjectId thread_id = Dbg::GetThreadId(basket.thread);
- if (VLOG_IS_ON(jdwp)) {
- LogMatchingEventsAndThread(match_list, match_count, thread_id);
- VLOG(jdwp) << " suspend_policy=" << suspend_policy;
- }
+ if (VLOG_IS_ON(jdwp)) {
+ LogMatchingEventsAndThread(match_list, thread_id);
+ VLOG(jdwp) << " suspend_policy=" << suspend_policy;
+ }
- pReq = eventPrep();
- expandBufAdd1(pReq, suspend_policy);
- expandBufAdd4BE(pReq, match_count);
+ ExpandBuf* pReq = eventPrep();
+ expandBufAdd1(pReq, suspend_policy);
+ expandBufAdd4BE(pReq, match_list.size());
- for (size_t i = 0; i < match_count; i++) {
- expandBufAdd1(pReq, match_list[i]->eventKind);
- expandBufAdd4BE(pReq, match_list[i]->requestId);
- expandBufAdd8BE(pReq, thread_id);
- }
- }
+ for (const JdwpEvent* pEvent : match_list) {
+ expandBufAdd1(pReq, pEvent->eventKind);
+ expandBufAdd4BE(pReq, pEvent->requestId);
+ expandBufAdd8BE(pReq, thread_id);
+ }
- {
- MutexLock mu(Thread::Current(), event_list_lock_);
- CleanupMatchList(match_list, match_count);
- }
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ CleanupMatchList(match_list);
}
Dbg::ManageDeoptimization();
SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
-
- return match_count != 0;
}
/*
@@ -1132,7 +1082,7 @@ bool JdwpState::PostVMDeath() {
* because there's a pretty good chance that we're not going to send it
* up the debugger.
*/
-bool JdwpState::PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object,
+void JdwpState::PostException(const EventLocation* pThrowLoc, mirror::Throwable* exception_object,
const EventLocation* pCatchLoc, mirror::Object* thisPtr) {
DCHECK(exception_object != nullptr);
DCHECK(pThrowLoc != nullptr);
@@ -1159,72 +1109,61 @@ bool JdwpState::PostException(const EventLocation* pThrowLoc, mirror::Throwable*
/* don't try to post an exception caused by the debugger */
if (InvokeInProgress()) {
VLOG(jdwp) << "Not posting exception hit during invoke (" << basket.className << ")";
- return false;
+ return;
}
- size_t match_count = 0;
- ExpandBuf* pReq = NULL;
- JdwpSuspendPolicy suspend_policy = SP_NONE;
- JdwpEvent** match_list = nullptr;
- ObjectId thread_id = 0;
- {
- {
- MutexLock mu(Thread::Current(), event_list_lock_);
- match_list = AllocMatchList(event_list_size_);
- FindMatchingEvents(EK_EXCEPTION, basket, match_list, &match_count);
- }
- if (match_count != 0) {
- suspend_policy = scanSuspendPolicy(match_list, match_count);
-
- thread_id = Dbg::GetThreadId(basket.thread);
- ObjectRegistry* registry = Dbg::GetObjectRegistry();
- ObjectId exceptionId = registry->Add(exception_object);
- JDWP::JdwpLocation jdwp_throw_location;
- JDWP::JdwpLocation jdwp_catch_location;
- SetJdwpLocationFromEventLocation(pThrowLoc, &jdwp_throw_location);
- SetJdwpLocationFromEventLocation(pCatchLoc, &jdwp_catch_location);
-
- if (VLOG_IS_ON(jdwp)) {
- std::string exceptionClassName(PrettyDescriptor(exception_object->GetClass()));
-
- LogMatchingEventsAndThread(match_list, match_count, thread_id);
- VLOG(jdwp) << " throwLocation=" << jdwp_throw_location;
- if (jdwp_catch_location.class_id == 0) {
- VLOG(jdwp) << " catchLocation=uncaught";
- } else {
- VLOG(jdwp) << " catchLocation=" << jdwp_catch_location;
- }
- VLOG(jdwp) << StringPrintf(" exception=%#" PRIx64, exceptionId) << " "
- << exceptionClassName;
- VLOG(jdwp) << " suspend_policy=" << suspend_policy;
- }
+ std::vector<JdwpEvent*> match_list;
+ if (!FindMatchingEvents(EK_EXCEPTION, basket, &match_list)) {
+ // No matching event.
+ return;
+ }
- pReq = eventPrep();
- expandBufAdd1(pReq, suspend_policy);
- expandBufAdd4BE(pReq, match_count);
-
- for (size_t i = 0; i < match_count; i++) {
- expandBufAdd1(pReq, match_list[i]->eventKind);
- expandBufAdd4BE(pReq, match_list[i]->requestId);
- expandBufAdd8BE(pReq, thread_id);
- expandBufAddLocation(pReq, jdwp_throw_location);
- expandBufAdd1(pReq, JT_OBJECT);
- expandBufAdd8BE(pReq, exceptionId);
- expandBufAddLocation(pReq, jdwp_catch_location);
- }
+ JdwpSuspendPolicy suspend_policy = ScanSuspendPolicy(match_list);
+ ObjectId thread_id = Dbg::GetThreadId(basket.thread);
+ ObjectRegistry* registry = Dbg::GetObjectRegistry();
+ ObjectId exceptionId = registry->Add(exception_object);
+ JDWP::JdwpLocation jdwp_throw_location;
+ JDWP::JdwpLocation jdwp_catch_location;
+ SetJdwpLocationFromEventLocation(pThrowLoc, &jdwp_throw_location);
+ SetJdwpLocationFromEventLocation(pCatchLoc, &jdwp_catch_location);
+
+ if (VLOG_IS_ON(jdwp)) {
+ std::string exceptionClassName(PrettyDescriptor(exception_object->GetClass()));
+
+ LogMatchingEventsAndThread(match_list, thread_id);
+ VLOG(jdwp) << " throwLocation=" << jdwp_throw_location;
+ if (jdwp_catch_location.class_id == 0) {
+ VLOG(jdwp) << " catchLocation=uncaught";
+ } else {
+ VLOG(jdwp) << " catchLocation=" << jdwp_catch_location;
}
+ VLOG(jdwp) << StringPrintf(" exception=%#" PRIx64, exceptionId) << " "
+ << exceptionClassName;
+ VLOG(jdwp) << " suspend_policy=" << suspend_policy;
+ }
- {
- MutexLock mu(Thread::Current(), event_list_lock_);
- CleanupMatchList(match_list, match_count);
- }
+ ExpandBuf* pReq = eventPrep();
+ expandBufAdd1(pReq, suspend_policy);
+ expandBufAdd4BE(pReq, match_list.size());
+
+ for (const JdwpEvent* pEvent : match_list) {
+ expandBufAdd1(pReq, pEvent->eventKind);
+ expandBufAdd4BE(pReq, pEvent->requestId);
+ expandBufAddObjectId(pReq, thread_id);
+ expandBufAddLocation(pReq, jdwp_throw_location);
+ expandBufAdd1(pReq, JT_OBJECT);
+ expandBufAddObjectId(pReq, exceptionId);
+ expandBufAddLocation(pReq, jdwp_catch_location);
+ }
+
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ CleanupMatchList(match_list);
}
Dbg::ManageDeoptimization();
SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
-
- return match_count != 0;
}
/*
@@ -1233,7 +1172,7 @@ bool JdwpState::PostException(const EventLocation* pThrowLoc, mirror::Throwable*
* Valid mods:
* Count, ThreadOnly, ClassOnly, ClassMatch, ClassExclude
*/
-bool JdwpState::PostClassPrepare(mirror::Class* klass) {
+void JdwpState::PostClassPrepare(mirror::Class* klass) {
DCHECK(klass != nullptr);
ModBasket basket;
@@ -1244,80 +1183,69 @@ bool JdwpState::PostClassPrepare(mirror::Class* klass) {
/* suppress class prep caused by debugger */
if (InvokeInProgress()) {
VLOG(jdwp) << "Not posting class prep caused by invoke (" << basket.className << ")";
- return false;
+ return;
}
- ExpandBuf* pReq = NULL;
- JdwpSuspendPolicy suspend_policy = SP_NONE;
- JdwpEvent** match_list = nullptr;
- size_t match_count = 0;
- ObjectId thread_id = 0;
- {
- {
- MutexLock mu(Thread::Current(), event_list_lock_);
- match_list = AllocMatchList(event_list_size_);
- FindMatchingEvents(EK_CLASS_PREPARE, basket, match_list, &match_count);
- }
- if (match_count != 0) {
- suspend_policy = scanSuspendPolicy(match_list, match_count);
-
- thread_id = Dbg::GetThreadId(basket.thread);
- ObjectRegistry* registry = Dbg::GetObjectRegistry();
- RefTypeId class_id = registry->AddRefType(basket.locationClass);
-
- // OLD-TODO - we currently always send both "verified" and "prepared" since
- // debuggers seem to like that. There might be some advantage to honesty,
- // since the class may not yet be verified.
- int status = JDWP::CS_VERIFIED | JDWP::CS_PREPARED;
- JDWP::JdwpTypeTag tag = Dbg::GetTypeTag(basket.locationClass);
- std::string temp;
- std::string signature(basket.locationClass->GetDescriptor(&temp));
-
- if (VLOG_IS_ON(jdwp)) {
- LogMatchingEventsAndThread(match_list, match_count, thread_id);
- VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, class_id) << " " << signature;
- VLOG(jdwp) << " suspend_policy=" << suspend_policy;
- }
+ std::vector<JdwpEvent*> match_list;
+ if (!FindMatchingEvents(EK_CLASS_PREPARE, basket, &match_list)) {
+ // No matching event.
+ return;
+ }
- if (thread_id == debug_thread_id_) {
- /*
- * JDWP says that, for a class prep in the debugger thread, we
- * should set thread to null and if any threads were supposed
- * to be suspended then we suspend all other threads.
- */
- VLOG(jdwp) << " NOTE: class prepare in debugger thread!";
- thread_id = 0;
- if (suspend_policy == SP_EVENT_THREAD) {
- suspend_policy = SP_ALL;
- }
- }
+ JdwpSuspendPolicy suspend_policy = ScanSuspendPolicy(match_list);
+ ObjectId thread_id = Dbg::GetThreadId(basket.thread);
+ ObjectRegistry* registry = Dbg::GetObjectRegistry();
+ RefTypeId class_id = registry->AddRefType(basket.locationClass);
+
+ // OLD-TODO - we currently always send both "verified" and "prepared" since
+ // debuggers seem to like that. There might be some advantage to honesty,
+ // since the class may not yet be verified.
+ int status = JDWP::CS_VERIFIED | JDWP::CS_PREPARED;
+ JDWP::JdwpTypeTag tag = Dbg::GetTypeTag(basket.locationClass);
+ std::string temp;
+ std::string signature(basket.locationClass->GetDescriptor(&temp));
+
+ if (VLOG_IS_ON(jdwp)) {
+ LogMatchingEventsAndThread(match_list, thread_id);
+ VLOG(jdwp) << StringPrintf(" type=%#" PRIx64, class_id) << " " << signature;
+ VLOG(jdwp) << " suspend_policy=" << suspend_policy;
+ }
- pReq = eventPrep();
- expandBufAdd1(pReq, suspend_policy);
- expandBufAdd4BE(pReq, match_count);
-
- for (size_t i = 0; i < match_count; i++) {
- expandBufAdd1(pReq, match_list[i]->eventKind);
- expandBufAdd4BE(pReq, match_list[i]->requestId);
- expandBufAdd8BE(pReq, thread_id);
- expandBufAdd1(pReq, tag);
- expandBufAdd8BE(pReq, class_id);
- expandBufAddUtf8String(pReq, signature);
- expandBufAdd4BE(pReq, status);
- }
+ if (thread_id == debug_thread_id_) {
+ /*
+ * JDWP says that, for a class prep in the debugger thread, we
+ * should set thread to null and if any threads were supposed
+ * to be suspended then we suspend all other threads.
+ */
+ VLOG(jdwp) << " NOTE: class prepare in debugger thread!";
+ thread_id = 0;
+ if (suspend_policy == SP_EVENT_THREAD) {
+ suspend_policy = SP_ALL;
}
+ }
- {
- MutexLock mu(Thread::Current(), event_list_lock_);
- CleanupMatchList(match_list, match_count);
- }
+ ExpandBuf* pReq = eventPrep();
+ expandBufAdd1(pReq, suspend_policy);
+ expandBufAdd4BE(pReq, match_list.size());
+
+ for (const JdwpEvent* pEvent : match_list) {
+ expandBufAdd1(pReq, pEvent->eventKind);
+ expandBufAdd4BE(pReq, pEvent->requestId);
+ expandBufAddObjectId(pReq, thread_id);
+ expandBufAdd1(pReq, tag);
+ expandBufAddRefTypeId(pReq, class_id);
+ expandBufAddUtf8String(pReq, signature);
+ expandBufAdd4BE(pReq, status);
+ }
+
+ {
+ MutexLock mu(Thread::Current(), event_list_lock_);
+ CleanupMatchList(match_list);
}
Dbg::ManageDeoptimization();
SendRequestAndPossiblySuspend(pReq, suspend_policy, thread_id);
-
- return match_count != 0;
}
/*
@@ -1331,7 +1259,7 @@ void JdwpState::DdmSendChunkV(uint32_t type, const iovec* iov, int iov_count) {
uint8_t header[kJDWPHeaderLen + 8];
size_t dataLen = 0;
- CHECK(iov != NULL);
+ CHECK(iov != nullptr);
CHECK_GT(iov_count, 0);
CHECK_LT(iov_count, 10);
@@ -1348,12 +1276,12 @@ void JdwpState::DdmSendChunkV(uint32_t type, const iovec* iov, int iov_count) {
/* form the header (JDWP plus DDMS) */
Set4BE(header, sizeof(header) + dataLen);
- Set4BE(header+4, NextRequestSerial());
- Set1(header+8, 0); /* flags */
- Set1(header+9, kJDWPDdmCmdSet);
- Set1(header+10, kJDWPDdmCmd);
- Set4BE(header+11, type);
- Set4BE(header+15, dataLen);
+ Set4BE(header + 4, NextRequestSerial());
+ Set1(header + 8, 0); /* flags */
+ Set1(header + 9, kJDWPDdmCmdSet);
+ Set1(header + 10, kJDWPDdmCmd);
+ Set4BE(header + 11, type);
+ Set4BE(header + 15, dataLen);
wrapiov[0].iov_base = header;
wrapiov[0].iov_len = sizeof(header);
@@ -1364,7 +1292,7 @@ void JdwpState::DdmSendChunkV(uint32_t type, const iovec* iov, int iov_count) {
bool safe_to_release_mutator_lock_over_send = !Locks::mutator_lock_->IsExclusiveHeld(self);
if (safe_to_release_mutator_lock_over_send) {
for (size_t i = 0; i < kMutatorLock; ++i) {
- if (self->GetHeldMutex(static_cast<LockLevel>(i)) != NULL) {
+ if (self->GetHeldMutex(static_cast<LockLevel>(i)) != nullptr) {
safe_to_release_mutator_lock_over_send = false;
break;
}
diff --git a/runtime/jdwp/jdwp_expand_buf.cc b/runtime/jdwp/jdwp_expand_buf.cc
index 0a64f28e11..cc85cdd72a 100644
--- a/runtime/jdwp/jdwp_expand_buf.cc
+++ b/runtime/jdwp/jdwp_expand_buf.cc
@@ -57,7 +57,7 @@ ExpandBuf* expandBufAlloc() {
* Free a JdwpBuf and associated storage.
*/
void expandBufFree(ExpandBuf* pBuf) {
- if (pBuf == NULL) {
+ if (pBuf == nullptr) {
return;
}
@@ -93,7 +93,7 @@ static void ensureSpace(ExpandBuf* pBuf, int newCount) {
}
uint8_t* newPtr = reinterpret_cast<uint8_t*>(realloc(pBuf->storage, pBuf->maxLen));
- if (newPtr == NULL) {
+ if (newPtr == nullptr) {
LOG(FATAL) << "realloc(" << pBuf->maxLen << ") failed";
}
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index a39a7b76fb..b294e480b8 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -106,8 +106,8 @@ static JdwpError FinishInvoke(JdwpState*, Request* request, ExpandBuf* pReply,
Dbg::GetMethodName(method_id).c_str());
VLOG(jdwp) << StringPrintf(" %d args:", arg_count);
- std::unique_ptr<JdwpTag[]> argTypes(arg_count > 0 ? new JdwpTag[arg_count] : NULL);
- std::unique_ptr<uint64_t[]> argValues(arg_count > 0 ? new uint64_t[arg_count] : NULL);
+ std::unique_ptr<JdwpTag[]> argTypes(arg_count > 0 ? new JdwpTag[arg_count] : nullptr);
+ std::unique_ptr<uint64_t[]> argValues(arg_count > 0 ? new uint64_t[arg_count] : nullptr);
for (int32_t i = 0; i < arg_count; ++i) {
argTypes[i] = request->ReadTag();
size_t width = Dbg::GetTagWidth(argTypes[i]);
@@ -124,7 +124,9 @@ static JdwpError FinishInvoke(JdwpState*, Request* request, ExpandBuf* pReply,
JdwpTag resultTag;
uint64_t resultValue;
ObjectId exceptObjId;
- JdwpError err = Dbg::InvokeMethod(thread_id, object_id, class_id, method_id, arg_count, argValues.get(), argTypes.get(), options, &resultTag, &resultValue, &exceptObjId);
+ JdwpError err = Dbg::InvokeMethod(thread_id, object_id, class_id, method_id, arg_count,
+ argValues.get(), argTypes.get(), options, &resultTag,
+ &resultValue, &exceptObjId);
if (err != ERR_NONE) {
return err;
}
@@ -203,7 +205,7 @@ static JdwpError VM_ClassesBySignature(JdwpState*, Request* request, ExpandBuf*
// Get class vs. interface and status flags.
JDWP::JdwpTypeTag type_tag;
uint32_t class_status;
- JDWP::JdwpError status = Dbg::GetClassInfo(ids[i], &type_tag, &class_status, NULL);
+ JDWP::JdwpError status = Dbg::GetClassInfo(ids[i], &type_tag, &class_status, nullptr);
if (status != ERR_NONE) {
return status;
}
@@ -371,7 +373,7 @@ static JdwpError VM_Capabilities(JdwpState*, Request*, ExpandBuf* reply)
static JdwpError VM_CapabilitiesNew(JdwpState*, Request* request, ExpandBuf* reply)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// The first few capabilities are the same as those reported by the older call.
- VM_Capabilities(NULL, request, reply);
+ VM_Capabilities(nullptr, request, reply);
expandBufAdd1(reply, false); // canRedefineClasses
expandBufAdd1(reply, false); // canAddMethod
@@ -507,7 +509,7 @@ static JdwpError RT_Status(JdwpState*, Request* request, ExpandBuf* pReply)
RefTypeId refTypeId = request->ReadRefTypeId();
JDWP::JdwpTypeTag type_tag;
uint32_t class_status;
- JDWP::JdwpError status = Dbg::GetClassInfo(refTypeId, &type_tag, &class_status, NULL);
+ JDWP::JdwpError status = Dbg::GetClassInfo(refTypeId, &type_tag, &class_status, nullptr);
if (status != ERR_NONE) {
return status;
}
@@ -1432,7 +1434,7 @@ static JdwpError COR_ReflectedType(JdwpState*, Request* request, ExpandBuf* pRep
static JdwpError DDM_Chunk(JdwpState* state, Request* request, ExpandBuf* pReply)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
state->NotifyDdmsActive();
- uint8_t* replyBuf = NULL;
+ uint8_t* replyBuf = nullptr;
int replyLen = -1;
if (Dbg::DdmHandlePacket(request, &replyBuf, &replyLen)) {
// If they want to send something back, we copy it into the buffer.
@@ -1481,11 +1483,11 @@ static const JdwpHandlerMap gHandlers[] = {
{ 1, 12, VM_Capabilities, "VirtualMachine.Capabilities" },
{ 1, 13, VM_ClassPaths, "VirtualMachine.ClassPaths" },
{ 1, 14, VM_DisposeObjects, "VirtualMachine.DisposeObjects" },
- { 1, 15, NULL, "VirtualMachine.HoldEvents" },
- { 1, 16, NULL, "VirtualMachine.ReleaseEvents" },
+ { 1, 15, nullptr, "VirtualMachine.HoldEvents" },
+ { 1, 16, nullptr, "VirtualMachine.ReleaseEvents" },
{ 1, 17, VM_CapabilitiesNew, "VirtualMachine.CapabilitiesNew" },
- { 1, 18, NULL, "VirtualMachine.RedefineClasses" },
- { 1, 19, NULL, "VirtualMachine.SetDefaultStratum" },
+ { 1, 18, nullptr, "VirtualMachine.RedefineClasses" },
+ { 1, 19, nullptr, "VirtualMachine.SetDefaultStratum" },
{ 1, 20, VM_AllClassesWithGeneric, "VirtualMachine.AllClassesWithGeneric" },
{ 1, 21, VM_InstanceCounts, "VirtualMachine.InstanceCounts" },
@@ -1497,7 +1499,7 @@ static const JdwpHandlerMap gHandlers[] = {
{ 2, 5, RT_Methods, "ReferenceType.Methods" },
{ 2, 6, RT_GetValues, "ReferenceType.GetValues" },
{ 2, 7, RT_SourceFile, "ReferenceType.SourceFile" },
- { 2, 8, NULL, "ReferenceType.NestedTypes" },
+ { 2, 8, nullptr, "ReferenceType.NestedTypes" },
{ 2, 9, RT_Status, "ReferenceType.Status" },
{ 2, 10, RT_Interfaces, "ReferenceType.Interfaces" },
{ 2, 11, RT_ClassObject, "ReferenceType.ClassObject" },
@@ -1506,8 +1508,8 @@ static const JdwpHandlerMap gHandlers[] = {
{ 2, 14, RT_FieldsWithGeneric, "ReferenceType.FieldsWithGeneric" },
{ 2, 15, RT_MethodsWithGeneric, "ReferenceType.MethodsWithGeneric" },
{ 2, 16, RT_Instances, "ReferenceType.Instances" },
- { 2, 17, NULL, "ReferenceType.ClassFileVersion" },
- { 2, 18, NULL, "ReferenceType.ConstantPool" },
+ { 2, 17, nullptr, "ReferenceType.ClassFileVersion" },
+ { 2, 18, nullptr, "ReferenceType.ConstantPool" },
/* ClassType command set (3) */
{ 3, 1, CT_Superclass, "ClassType.Superclass" },
@@ -1524,7 +1526,7 @@ static const JdwpHandlerMap gHandlers[] = {
{ 6, 1, M_LineTable, "Method.LineTable" },
{ 6, 2, M_VariableTable, "Method.VariableTable" },
{ 6, 3, M_Bytecodes, "Method.Bytecodes" },
- { 6, 4, NULL, "Method.IsObsolete" },
+ { 6, 4, nullptr, "Method.IsObsolete" },
{ 6, 5, M_VariableTableWithGeneric, "Method.VariableTableWithGeneric" },
/* Field command set (8) */
@@ -1533,7 +1535,7 @@ static const JdwpHandlerMap gHandlers[] = {
{ 9, 1, OR_ReferenceType, "ObjectReference.ReferenceType" },
{ 9, 2, OR_GetValues, "ObjectReference.GetValues" },
{ 9, 3, OR_SetValues, "ObjectReference.SetValues" },
- { 9, 4, NULL, "ObjectReference.UNUSED" },
+ { 9, 4, nullptr, "ObjectReference.UNUSED" },
{ 9, 5, OR_MonitorInfo, "ObjectReference.MonitorInfo" },
{ 9, 6, OR_InvokeMethod, "ObjectReference.InvokeMethod" },
{ 9, 7, OR_DisableCollection, "ObjectReference.DisableCollection" },
@@ -1554,11 +1556,11 @@ static const JdwpHandlerMap gHandlers[] = {
{ 11, 7, TR_FrameCount, "ThreadReference.FrameCount" },
{ 11, 8, TR_OwnedMonitors, "ThreadReference.OwnedMonitors" },
{ 11, 9, TR_CurrentContendedMonitor, "ThreadReference.CurrentContendedMonitor" },
- { 11, 10, NULL, "ThreadReference.Stop" },
+ { 11, 10, nullptr, "ThreadReference.Stop" },
{ 11, 11, TR_Interrupt, "ThreadReference.Interrupt" },
{ 11, 12, TR_DebugSuspendCount, "ThreadReference.SuspendCount" },
{ 11, 13, TR_OwnedMonitorsStackDepthInfo, "ThreadReference.OwnedMonitorsStackDepthInfo" },
- { 11, 14, NULL, "ThreadReference.ForceEarlyReturn" },
+ { 11, 14, nullptr, "ThreadReference.ForceEarlyReturn" },
/* ThreadGroupReference command set (12) */
{ 12, 1, TGR_Name, "ThreadGroupReference.Name" },
@@ -1576,26 +1578,27 @@ static const JdwpHandlerMap gHandlers[] = {
/* EventRequest command set (15) */
{ 15, 1, ER_Set, "EventRequest.Set" },
{ 15, 2, ER_Clear, "EventRequest.Clear" },
- { 15, 3, NULL, "EventRequest.ClearAllBreakpoints" },
+ { 15, 3, nullptr, "EventRequest.ClearAllBreakpoints" },
/* StackFrame command set (16) */
{ 16, 1, SF_GetValues, "StackFrame.GetValues" },
{ 16, 2, SF_SetValues, "StackFrame.SetValues" },
{ 16, 3, SF_ThisObject, "StackFrame.ThisObject" },
- { 16, 4, NULL, "StackFrame.PopFrames" },
+ { 16, 4, nullptr, "StackFrame.PopFrames" },
/* ClassObjectReference command set (17) */
{ 17, 1, COR_ReflectedType, "ClassObjectReference.ReflectedType" },
/* Event command set (64) */
- { 64, 100, NULL, "Event.Composite" }, // sent from VM to debugger, never received by VM
+ { 64, 100, nullptr, "Event.Composite" }, // sent from VM to debugger, never received by VM
{ 199, 1, DDM_Chunk, "DDM.Chunk" },
};
static const char* GetCommandName(Request* request) {
for (size_t i = 0; i < arraysize(gHandlers); ++i) {
- if (gHandlers[i].cmdSet == request->GetCommandSet() && gHandlers[i].cmd == request->GetCommand()) {
+ if (gHandlers[i].cmdSet == request->GetCommandSet() &&
+ gHandlers[i].cmd == request->GetCommand()) {
return gHandlers[i].name;
}
}
@@ -1663,7 +1666,9 @@ size_t JdwpState::ProcessRequest(Request* request, ExpandBuf* pReply) {
size_t i;
for (i = 0; i < arraysize(gHandlers); ++i) {
- if (gHandlers[i].cmdSet == request->GetCommandSet() && gHandlers[i].cmd == request->GetCommand() && gHandlers[i].func != NULL) {
+ if (gHandlers[i].cmdSet == request->GetCommandSet() &&
+ gHandlers[i].cmd == request->GetCommand() &&
+ gHandlers[i].func != nullptr) {
VLOG(jdwp) << DescribeCommand(request);
result = (*gHandlers[i].func)(this, request, pReply);
if (result == ERR_NONE) {
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index c500ef5311..bfd4252a5a 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -139,7 +139,7 @@ ssize_t JdwpNetStateBase::WriteBufferedPacket(const std::vector<iovec>& iov) {
}
bool JdwpState::IsConnected() {
- return netState != NULL && netState->IsConnected();
+ return netState != nullptr && netState->IsConnected();
}
void JdwpState::SendBufferedRequest(uint32_t type, const std::vector<iovec>& iov) {
@@ -202,18 +202,18 @@ JdwpState::JdwpState(const JdwpOptions* options)
thread_start_lock_("JDWP thread start lock", kJdwpStartLock),
thread_start_cond_("JDWP thread start condition variable", thread_start_lock_),
pthread_(0),
- thread_(NULL),
+ thread_(nullptr),
debug_thread_started_(false),
debug_thread_id_(0),
run(false),
- netState(NULL),
+ netState(nullptr),
attach_lock_("JDWP attach lock", kJdwpAttachLock),
attach_cond_("JDWP attach condition variable", attach_lock_),
last_activity_time_ms_(0),
request_serial_(0x10000000),
event_serial_(0x20000000),
event_list_lock_("JDWP event list lock", kJdwpEventListLock),
- event_list_(NULL),
+ event_list_(nullptr),
event_list_size_(0),
event_thread_lock_("JDWP event thread lock"),
event_thread_cond_("JDWP event thread condition variable", event_thread_lock_),
@@ -289,7 +289,7 @@ JdwpState* JdwpState::Create(const JdwpOptions* options) {
}
if (!state->IsActive()) {
LOG(ERROR) << "JDWP connection failed";
- return NULL;
+ return nullptr;
}
LOG(INFO) << "JDWP connected";
@@ -317,7 +317,7 @@ void JdwpState::ResetState() {
UnregisterAll();
{
MutexLock mu(Thread::Current(), event_list_lock_);
- CHECK(event_list_ == NULL);
+ CHECK(event_list_ == nullptr);
}
Dbg::ProcessDelayedFullUndeoptimizations();
@@ -336,7 +336,7 @@ void JdwpState::ResetState() {
* Tell the JDWP thread to shut down. Frees "state".
*/
JdwpState::~JdwpState() {
- if (netState != NULL) {
+ if (netState != nullptr) {
/*
* Close down the network to inspire the thread to halt.
*/
@@ -353,9 +353,9 @@ JdwpState::~JdwpState() {
VLOG(jdwp) << "JDWP freeing netstate...";
delete netState;
- netState = NULL;
+ netState = nullptr;
}
- CHECK(netState == NULL);
+ CHECK(netState == nullptr);
ResetState();
}
@@ -398,10 +398,10 @@ bool JdwpState::HandlePacket() {
*/
static void* StartJdwpThread(void* arg) {
JdwpState* state = reinterpret_cast<JdwpState*>(arg);
- CHECK(state != NULL);
+ CHECK(state != nullptr);
state->Run();
- return NULL;
+ return nullptr;
}
void JdwpState::Run() {
diff --git a/runtime/jdwp/jdwp_socket.cc b/runtime/jdwp/jdwp_socket.cc
index 7119ce5dbb..cbdde24ae6 100644
--- a/runtime/jdwp/jdwp_socket.cc
+++ b/runtime/jdwp/jdwp_socket.cc
@@ -77,12 +77,12 @@ bool InitSocketTransport(JdwpState* state, const JdwpOptions* options) {
/* scan through a range of ports, binding to the first available */
for (port = kBasePort; port <= kMaxPort; port++) {
state->netState = SocketStartup(state, port, true);
- if (state->netState != NULL) {
+ if (state->netState != nullptr) {
break;
}
}
}
- if (state->netState == NULL) {
+ if (state->netState == nullptr) {
LOG(ERROR) << "JDWP net startup failed (req port=" << options->port << ")";
return false;
}
@@ -157,7 +157,7 @@ static JdwpSocketState* SocketStartup(JdwpState* state, uint16_t port, bool prob
fail:
netState->Shutdown();
delete netState;
- return NULL;
+ return nullptr;
}
/*
@@ -284,7 +284,7 @@ bool JdwpSocketState::Establish(const JdwpOptions* options) {
#else
h_errno = 0;
pEntry = gethostbyname(options->host.c_str());
- if (pEntry == NULL) {
+ if (pEntry == nullptr) {
PLOG(WARNING) << "gethostbyname('" << options->host << "') failed";
return false;
}
@@ -403,7 +403,7 @@ bool JdwpSocketState::ProcessIncoming() {
* re-issue the select. We're currently using #2, as it's more
* reliable than #1 and generally better than #3. Wastes two fds.
*/
- selCount = select(maxfd+1, &readfds, NULL, NULL, NULL);
+ selCount = select(maxfd + 1, &readfds, nullptr, nullptr, nullptr);
if (selCount < 0) {
if (errno == EINTR) {
continue;
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index 91239944fe..20db368c21 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -138,7 +138,7 @@ mirror::Object* ObjectRegistry::InternalGet(JDWP::ObjectId id, JDWP::JdwpError*
jobject ObjectRegistry::GetJObject(JDWP::ObjectId id) {
if (id == 0) {
- return NULL;
+ return nullptr;
}
Thread* self = Thread::Current();
MutexLock mu(self, lock_);
@@ -194,7 +194,7 @@ bool ObjectRegistry::IsCollected(JDWP::ObjectId id) {
ObjectRegistryEntry& entry = *it->second;
if (entry.jni_reference_type == JNIWeakGlobalRefType) {
JNIEnv* env = self->GetJniEnv();
- return env->IsSameObject(entry.jni_reference, NULL); // Has the jweak been collected?
+ return env->IsSameObject(entry.jni_reference, nullptr); // Has the jweak been collected?
} else {
return false; // We hold a strong reference, so we know this is live.
}
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 29e061a7db..f33ca943d7 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -26,6 +26,7 @@
#include "object_callbacks.h"
#include "quick/quick_method_frame_info.h"
#include "read_barrier_option.h"
+#include "stack.h"
#include "stack_map.h"
namespace art {
@@ -390,8 +391,9 @@ class MANAGED ArtMethod FINAL : public Object {
}
FrameOffset GetHandleScopeOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- DCHECK_LT(sizeof(void*), GetFrameSizeInBytes());
- return FrameOffset(sizeof(void*));
+ constexpr size_t handle_scope_offset = sizeof(StackReference<mirror::ArtMethod>);
+ DCHECK_LT(handle_scope_offset, GetFrameSizeInBytes());
+ return FrameOffset(handle_scope_offset);
}
void RegisterNative(const void* native_method, bool is_fast)
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 2308cc9f11..4a7103b141 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1210,7 +1210,10 @@ void Thread::Destroy() {
tlsPtr_.opeer = nullptr;
}
- Runtime::Current()->GetHeap()->RevokeThreadLocalBuffers(this);
+ {
+ ScopedObjectAccess soa(self);
+ Runtime::Current()->GetHeap()->RevokeThreadLocalBuffers(this);
+ }
}
Thread::~Thread() {
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 65a8bd04ad..968e89d1da 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -27,6 +27,7 @@
#include <sstream>
+#include "base/histogram-inl.h"
#include "base/mutex.h"
#include "base/mutex-inl.h"
#include "base/timing_logger.h"
@@ -46,7 +47,8 @@ static constexpr uint64_t kLongThreadSuspendThreshold = MsToNs(5);
ThreadList::ThreadList()
: suspend_all_count_(0), debug_suspend_all_count_(0),
- thread_exit_cond_("thread exit condition variable", *Locks::thread_list_lock_) {
+ thread_exit_cond_("thread exit condition variable", *Locks::thread_list_lock_),
+ suspend_all_historam_("suspend all histogram", 16, 64) {
CHECK(Monitor::IsValidLockWord(LockWord::FromThinLockId(kMaxThreadId, 1)));
}
@@ -97,6 +99,12 @@ void ThreadList::DumpNativeStacks(std::ostream& os) {
}
void ThreadList::DumpForSigQuit(std::ostream& os) {
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ Histogram<uint64_t>::CumulativeData data;
+ suspend_all_historam_.CreateHistogram(&data);
+ suspend_all_historam_.PrintConfidenceIntervals(os, 0.99, data); // Dump time to suspend.
+ }
Dump(os);
DumpUnattachedThreads(os);
}
@@ -351,7 +359,7 @@ void ThreadList::SuspendAll() {
VLOG(threads) << "Thread[null] SuspendAll starting...";
}
ATRACE_BEGIN("Suspending mutator threads");
- uint64_t start_time = NanoTime();
+ const uint64_t start_time = NanoTime();
Locks::mutator_lock_->AssertNotHeld(self);
Locks::thread_list_lock_->AssertNotHeld(self);
@@ -384,9 +392,11 @@ void ThreadList::SuspendAll() {
Locks::mutator_lock_->ExclusiveLock(self);
#endif
- uint64_t end_time = NanoTime();
- if (end_time - start_time > kLongThreadSuspendThreshold) {
- LOG(WARNING) << "Suspending all threads took: " << PrettyDuration(end_time - start_time);
+ const uint64_t end_time = NanoTime();
+ const uint64_t suspend_time = end_time - start_time;
+ suspend_all_historam_.AdjustAndAddValue(suspend_time);
+ if (suspend_time > kLongThreadSuspendThreshold) {
+ LOG(WARNING) << "Suspending all threads took: " << PrettyDuration(suspend_time);
}
if (kDebugLocking) {
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index 13684c7668..43c065ae0a 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -17,6 +17,7 @@
#ifndef ART_RUNTIME_THREAD_LIST_H_
#define ART_RUNTIME_THREAD_LIST_H_
+#include "base/histogram.h"
#include "base/mutex.h"
#include "jni.h"
#include "object_callbacks.h"
@@ -39,11 +40,10 @@ class ThreadList {
~ThreadList();
void DumpForSigQuit(std::ostream& os)
- LOCKS_EXCLUDED(Locks::thread_list_lock_);
+ LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::mutator_lock_);
// For thread suspend timeout dumps.
void Dump(std::ostream& os)
- LOCKS_EXCLUDED(Locks::thread_list_lock_,
- Locks::thread_suspend_count_lock_);
+ LOCKS_EXCLUDED(Locks::thread_list_lock_, Locks::thread_suspend_count_lock_);
pid_t GetLockOwner(); // For SignalCatcher.
// Thread suspension support.
@@ -169,6 +169,10 @@ class ThreadList {
// Signaled when threads terminate. Used to determine when all non-daemons have terminated.
ConditionVariable thread_exit_cond_ GUARDED_BY(Locks::thread_list_lock_);
+ // Thread suspend time histogram. Only modified when all the threads are suspended, so guarding
+ // by mutator lock ensures no thread can read when another thread is modifying it.
+ Histogram<uint64_t> suspend_all_historam_ GUARDED_BY(Locks::mutator_lock_);
+
friend class Thread;
DISALLOW_COPY_AND_ASSIGN(ThreadList);