Skip to content

Commit f887b03

Browse files
committed
- Assert that we do not hold the timeline lock while entering
potential safepoints. - Enable timeline for existing test as a regression test. - Fix allocation with timeline lock held during deoptimization to prevent deadlock. BUG= [email protected] Review URL: https://codereview.chromium.org/1514653002 .
1 parent e78c269 commit f887b03

File tree

5 files changed

+78
-52
lines changed

5 files changed

+78
-52
lines changed

runtime/vm/deopt_instructions.cc

Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ DeoptContext::DeoptContext(const StackFrame* frame,
4343
deopt_reason_(ICData::kDeoptUnknown),
4444
deopt_flags_(0),
4545
thread_(Thread::Current()),
46-
timeline_event_(NULL),
46+
deopt_start_micros_(0),
4747
deferred_slots_(NULL),
4848
deferred_objects_count_(0),
4949
deferred_objects_(NULL),
@@ -99,14 +99,7 @@ DeoptContext::DeoptContext(const StackFrame* frame,
9999
if (dest_options != kDestIsAllocated) {
100100
// kDestIsAllocated is used by the debugger to generate a stack trace
101101
// and does not signal a real deopt.
102-
Isolate* isolate = Isolate::Current();
103-
TimelineStream* compiler_stream = isolate->GetCompilerStream();
104-
ASSERT(compiler_stream != NULL);
105-
timeline_event_ = compiler_stream->StartEvent();
106-
if (timeline_event_ != NULL) {
107-
timeline_event_->DurationBegin("Deoptimize");
108-
timeline_event_->SetNumArguments(3);
109-
}
102+
deopt_start_micros_ = OS::GetCurrentMonotonicMicros();
110103
}
111104

112105
if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
@@ -143,24 +136,28 @@ DeoptContext::~DeoptContext() {
143136
delete[] deferred_objects_;
144137
deferred_objects_ = NULL;
145138
deferred_objects_count_ = 0;
146-
if (timeline_event_ != NULL) {
147-
const Code& code = Code::Handle(zone(), code_);
148-
const Function& function = Function::Handle(zone(), code.function());
149-
timeline_event_->CopyArgument(
150-
0,
151-
"function",
152-
const_cast<char*>(function.QualifiedUserVisibleNameCString()));
153-
timeline_event_->CopyArgument(
154-
1,
155-
"reason",
156-
const_cast<char*>(DeoptReasonToCString(deopt_reason())));
157-
timeline_event_->FormatArgument(
158-
2,
159-
"deoptimizationCount",
160-
"%d",
161-
function.deoptimization_counter());
162-
timeline_event_->DurationEnd();
163-
timeline_event_->Complete();
139+
if (deopt_start_micros_ != 0) {
140+
Isolate* isolate = Isolate::Current();
141+
TimelineStream* compiler_stream = isolate->GetCompilerStream();
142+
ASSERT(compiler_stream != NULL);
143+
if (compiler_stream->Enabled()) {
144+
const Code& code = Code::Handle(zone(), code_);
145+
const Function& function = Function::Handle(zone(), code.function());
146+
const char* function_name = function.QualifiedUserVisibleNameCString();
147+
const char* reason = DeoptReasonToCString(deopt_reason());
148+
int counter = function.deoptimization_counter();
149+
TimelineEvent* timeline_event = compiler_stream->StartEvent();
150+
if (timeline_event != NULL) {
151+
timeline_event->Duration("Deoptimize",
152+
deopt_start_micros_,
153+
OS::GetCurrentMonotonicMicros());
154+
timeline_event->SetNumArguments(3);
155+
timeline_event->CopyArgument(0, "function", function_name);
156+
timeline_event->CopyArgument(1, "reason", reason);
157+
timeline_event->FormatArgument(2, "deoptimizationCount", "%d", counter);
158+
timeline_event->Complete();
159+
}
160+
}
164161
}
165162
}
166163

runtime/vm/deopt_instructions.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ class DeoptContext {
224224
uint32_t deopt_flags_;
225225
intptr_t caller_fp_;
226226
Thread* thread_;
227-
TimelineEvent* timeline_event_;
227+
int64_t deopt_start_micros_;
228228

229229
DeferredSlot* deferred_slots_;
230230

runtime/vm/timeline.cc

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -189,67 +189,68 @@ void TimelineEvent::Reset() {
189189

190190
void TimelineEvent::AsyncBegin(const char* label, int64_t async_id) {
191191
Init(kAsyncBegin, label);
192-
timestamp0_ = OS::GetCurrentMonotonicMicros();
192+
set_timestamp0(OS::GetCurrentMonotonicMicros());
193193
// Overload timestamp1_ with the async_id.
194-
timestamp1_ = async_id;
194+
set_timestamp1(async_id);
195195
}
196196

197197

198198
void TimelineEvent::AsyncInstant(const char* label,
199199
int64_t async_id) {
200200
Init(kAsyncInstant, label);
201-
timestamp0_ = OS::GetCurrentMonotonicMicros();
201+
set_timestamp0(OS::GetCurrentMonotonicMicros());
202202
// Overload timestamp1_ with the async_id.
203-
timestamp1_ = async_id;
203+
set_timestamp1(async_id);
204204
}
205205

206206

207207
void TimelineEvent::AsyncEnd(const char* label,
208208
int64_t async_id) {
209209
Init(kAsyncEnd, label);
210-
timestamp0_ = OS::GetCurrentMonotonicMicros();
210+
set_timestamp0(OS::GetCurrentMonotonicMicros());
211211
// Overload timestamp1_ with the async_id.
212-
timestamp1_ = async_id;
212+
set_timestamp1(async_id);
213213
}
214214

215215

216216
void TimelineEvent::DurationBegin(const char* label) {
217217
Init(kDuration, label);
218-
timestamp0_ = OS::GetCurrentMonotonicMicros();
218+
set_timestamp0(OS::GetCurrentMonotonicMicros());
219219
}
220220

221221

222222
void TimelineEvent::DurationEnd() {
223-
timestamp1_ = OS::GetCurrentMonotonicMicros();
223+
ASSERT(timestamp1_ == 0);
224+
set_timestamp1(OS::GetCurrentMonotonicMicros());
224225
}
225226

226227

227228
void TimelineEvent::Instant(const char* label) {
228229
Init(kInstant, label);
229-
timestamp0_ = OS::GetCurrentMonotonicMicros();
230+
set_timestamp0(OS::GetCurrentMonotonicMicros());
230231
}
231232

232233

233234
void TimelineEvent::Duration(const char* label,
234235
int64_t start_micros,
235236
int64_t end_micros) {
236237
Init(kDuration, label);
237-
timestamp0_ = start_micros;
238-
timestamp1_ = end_micros;
238+
set_timestamp0(start_micros);
239+
set_timestamp1(end_micros);
239240
}
240241

241242

242243
void TimelineEvent::Begin(const char* label,
243244
int64_t micros) {
244245
Init(kBegin, label);
245-
timestamp0_ = micros;
246+
set_timestamp0(micros);
246247
}
247248

248249

249250
void TimelineEvent::End(const char* label,
250251
int64_t micros) {
251252
Init(kEnd, label);
252-
timestamp0_ = micros;
253+
set_timestamp0(micros);
253254
}
254255

255256

@@ -675,6 +676,12 @@ TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() {
675676
// We are accessing the thread's timeline block- so take the lock here.
676677
// This lock will be held until the call to |CompleteEvent| is made.
677678
thread_block_lock->Lock();
679+
#if defined(DEBUG)
680+
Thread* T = Thread::Current();
681+
if (T != NULL) {
682+
T->IncrementNoSafepointScopeDepth();
683+
}
684+
#endif // defined(DEBUG)
678685

679686
TimelineEventBlock* thread_block = thread->timeline_block();
680687

@@ -699,6 +706,11 @@ TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() {
699706
return event;
700707
}
701708
// Drop lock here as no event is being handed out.
709+
#if defined(DEBUG)
710+
if (T != NULL) {
711+
T->DecrementNoSafepointScopeDepth();
712+
}
713+
#endif // defined(DEBUG)
702714
thread_block_lock->Unlock();
703715
return NULL;
704716
}
@@ -714,6 +726,12 @@ void TimelineEventRecorder::ThreadBlockCompleteEvent(TimelineEvent* event) {
714726
// Unlock the thread's block lock.
715727
Mutex* thread_block_lock = thread->timeline_block_lock();
716728
ASSERT(thread_block_lock != NULL);
729+
#if defined(DEBUG)
730+
Thread* T = Thread::Current();
731+
if (T != NULL) {
732+
T->DecrementNoSafepointScopeDepth();
733+
}
734+
#endif // defined(DEBUG)
717735
thread_block_lock->Unlock();
718736
}
719737

runtime/vm/timeline.h

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -236,16 +236,6 @@ class TimelineEvent {
236236
const char* GetSerializedJSON() const;
237237

238238
private:
239-
int64_t timestamp0_;
240-
int64_t timestamp1_;
241-
TimelineEventArgument* arguments_;
242-
intptr_t arguments_length_;
243-
uword state_;
244-
const char* label_;
245-
const char* category_;
246-
ThreadId thread_;
247-
Dart_Port isolate_id_;
248-
249239
void FreeArguments();
250240

251241
void StreamInit(TimelineStream* stream);
@@ -257,13 +247,32 @@ class TimelineEvent {
257247
state_ = EventTypeField::update(event_type, state_);
258248
}
259249

250+
void set_timestamp0(int64_t value) {
251+
ASSERT(timestamp0_ == 0);
252+
timestamp0_ = value;
253+
}
254+
void set_timestamp1(int64_t value) {
255+
ASSERT(timestamp1_ == 0);
256+
timestamp1_ = value;
257+
}
258+
260259
enum StateBits {
261260
kEventTypeBit = 0, // reserve 4 bits for type.
262261
kNextBit = 4,
263262
};
264263

265264
class EventTypeField : public BitField<EventType, kEventTypeBit, 4> {};
266265

266+
int64_t timestamp0_;
267+
int64_t timestamp1_;
268+
TimelineEventArgument* arguments_;
269+
intptr_t arguments_length_;
270+
uword state_;
271+
const char* label_;
272+
const char* category_;
273+
ThreadId thread_;
274+
Dart_Port isolate_id_;
275+
267276
friend class TimelineEventRecorder;
268277
friend class TimelineEventEndlessRecorder;
269278
friend class TimelineEventRingRecorder;

tests/standalone/array_bounds_check_generalization_test.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44
//
5-
// VMOptions=--optimization_counter_threshold=10 --no-use-osr
5+
// We are using --complete-timeline below to ensure that we get timeline events
6+
// generated during all phases of compilation and deoptimization.
7+
// VMOptions=--optimization_counter_threshold=10 --no-use-osr --complete-timeline
68

79
import "package:expect/expect.dart";
810

0 commit comments

Comments
 (0)