Skip to content

Commit 499b5b2

Browse files
rmacnak-googlecommit-bot@chromium.org
authored andcommitted
[vm] Don't touch the PCMarker slot in the Dart profiler walker.
- The PCMarker slot may be uninitialized (okay, a few skipped samples) and on a guard page (not okay, crash). - With the upcoming "bare instructions" mode, some Dart frames will lack a PC marker slot. Instead, add a sentinel value to the entry frame *above* its FP. Change-Id: I70d737a6f2f76febe61fe774932127f5274565b1 Reviewed-on: https://dart-review.googlesource.com/c/86502 Commit-Queue: Ryan Macnak <[email protected]> Reviewed-by: Régis Crelier <[email protected]>
1 parent 4288fe9 commit 499b5b2

File tree

7 files changed

+53
-78
lines changed

7 files changed

+53
-78
lines changed

runtime/vm/interpreter.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3019,11 +3019,6 @@ void Interpreter::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
30193019
// in the previous C++ frames.
30203020
StackResource::Unwind(thread);
30213021

3022-
// Set the tag.
3023-
thread->set_vm_tag(VMTag::kDartInterpretedTagId);
3024-
// Clear top exit frame.
3025-
thread->set_top_exit_frame_info(0);
3026-
30273022
fp_ = reinterpret_cast<RawObject**>(fp);
30283023

30293024
if (pc == StubCode::RunExceptionHandler().EntryPoint()) {
@@ -3041,6 +3036,11 @@ void Interpreter::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
30413036
pc_ = pc;
30423037
}
30433038

3039+
// Set the tag.
3040+
thread->set_vm_tag(VMTag::kDartInterpretedTagId);
3041+
// Clear top exit frame.
3042+
thread->set_top_exit_frame_info(0);
3043+
30443044
buf->Longjmp();
30453045
UNREACHABLE();
30463046
}

runtime/vm/profiler.cc

Lines changed: 27 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -515,11 +515,8 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
515515
ProfilerDartStackWalker(Thread* thread,
516516
Sample* sample,
517517
SampleBuffer* sample_buffer,
518-
uword stack_lower,
519-
uword stack_upper,
520518
uword pc,
521519
uword fp,
522-
uword sp,
523520
bool allocation_sample,
524521
intptr_t skip_count = 0)
525522
: ProfilerStackWalker((thread->isolate() != NULL)
@@ -530,10 +527,7 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
530527
skip_count),
531528
thread_(thread),
532529
pc_(reinterpret_cast<uword*>(pc)),
533-
fp_(reinterpret_cast<uword*>(fp)),
534-
sp_(reinterpret_cast<uword*>(sp)),
535-
stack_upper_(stack_upper),
536-
stack_lower_(stack_lower) {}
530+
fp_(reinterpret_cast<uword*>(fp)) {}
537531

538532
bool IsInterpretedFrame(uword* fp) {
539533
#if defined(DART_PRECOMPILED_RUNTIME)
@@ -600,6 +594,19 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
600594

601595
sample_->set_exit_frame_sample(has_exit_frame);
602596

597+
if (!has_exit_frame && !in_interpreted_frame &&
598+
(CallerPC(in_interpreted_frame) == EntryMarker(in_interpreted_frame))) {
599+
// During the prologue of a function, CallerPC will return the caller's
600+
// caller. For most frames, the missing PC will be added during profile
601+
// processing. However, during this stack walk, it can cause us to fail
602+
// to identify the entry frame and lead the stack walk into the weeds.
603+
// Do not continue the stalk walk since this might be a false positive
604+
// from a Smi or unboxed value.
605+
RELEASE_ASSERT(!has_exit_frame);
606+
sample_->set_ignore_sample(true);
607+
return;
608+
}
609+
603610
for (;;) {
604611
// Skip entry frame.
605612
if (StubCode::InInvocationStub(reinterpret_cast<uword>(pc_),
@@ -620,20 +627,6 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
620627
in_interpreted_frame));
621628
}
622629

623-
#if !defined(TARGET_ARCH_DBC)
624-
RawCode* marker = PCMarker(in_interpreted_frame);
625-
if (marker == StubCode::InvokeDartCode().raw() ||
626-
marker == StubCode::InvokeDartCodeFromBytecode().raw()) {
627-
// During the prologue of a function, CallerPC will return the caller's
628-
// caller. For most frames, the missing PC will be added during profile
629-
// processing. However, during this stack walk, it can cause us to fail
630-
// to identify the entry frame and lead the stack walk into the weeds.
631-
RELEASE_ASSERT(!has_exit_frame);
632-
sample_->set_ignore_sample(true);
633-
return;
634-
}
635-
#endif
636-
637630
if (!Append(reinterpret_cast<uword>(pc_))) {
638631
break; // Sample is full.
639632
}
@@ -648,14 +641,6 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
648641
}
649642

650643
private:
651-
uword InitialReturnAddress() const {
652-
ASSERT(sp_ != NULL);
653-
// MSan/ASan are unaware of frames initialized by generated code.
654-
MSAN_UNPOISON(sp_, kWordSize);
655-
ASAN_UNPOISON(sp_, kWordSize);
656-
return *(sp_);
657-
}
658-
659644
uword* CallerPC(bool interp) const {
660645
ASSERT(fp_ != NULL);
661646
uword* caller_pc_ptr =
@@ -676,20 +661,6 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
676661
return reinterpret_cast<uword*>(*caller_fp_ptr);
677662
}
678663

679-
RawCode* PCMarker(bool interp) const {
680-
ASSERT(fp_ != NULL);
681-
if (interp) {
682-
// We don't need this extra check for the interpreter because its frame
683-
// build is atomic from the profiler's point of view.
684-
return NULL;
685-
}
686-
uword* pc_marker_ptr = fp_ + kPcMarkerSlotFromFp;
687-
// MSan/ASan are unaware of frames initialized by generated code.
688-
MSAN_UNPOISON(pc_marker_ptr, kWordSize);
689-
ASAN_UNPOISON(pc_marker_ptr, kWordSize);
690-
return reinterpret_cast<RawCode*>(*pc_marker_ptr);
691-
}
692-
693664
uword* ExitLink(bool interp) const {
694665
ASSERT(fp_ != NULL);
695666
uword* exit_link_ptr =
@@ -700,23 +671,21 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
700671
return reinterpret_cast<uword*>(*exit_link_ptr);
701672
}
702673

703-
bool ValidFramePointer() const { return ValidFramePointer(fp_); }
704-
705-
bool ValidFramePointer(uword* fp) const {
706-
if (fp == NULL) {
707-
return false;
708-
}
709-
uword cursor = reinterpret_cast<uword>(fp);
710-
cursor += sizeof(fp);
711-
return (cursor >= stack_lower_) && (cursor < stack_upper_);
674+
// Note because of stack guards, it is important that this marker lives
675+
// above FP.
676+
uword* EntryMarker(bool interp) const {
677+
ASSERT(!interp);
678+
ASSERT(fp_ != NULL);
679+
uword* entry_marker_ptr = fp_ + kSavedCallerPcSlotFromFp + 1;
680+
// MSan/ASan are unaware of frames initialized by generated code.
681+
MSAN_UNPOISON(entry_marker_ptr, kWordSize);
682+
ASAN_UNPOISON(entry_marker_ptr, kWordSize);
683+
return reinterpret_cast<uword*>(*entry_marker_ptr);
712684
}
713685

714686
Thread* const thread_;
715687
uword* pc_;
716688
uword* fp_;
717-
uword* sp_;
718-
const uword stack_upper_;
719-
const uword stack_lower_;
720689
};
721690

722691
// If the VM is compiled without frame pointers (which is the default on
@@ -1218,8 +1187,7 @@ void Profiler::SampleAllocation(Thread* thread, intptr_t cid) {
12181187
native_stack_walker.walk();
12191188
} else if (exited_dart_code) {
12201189
ProfilerDartStackWalker dart_exit_stack_walker(
1221-
thread, sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp,
1222-
/* allocation_sample*/ true);
1190+
thread, sample, sample_buffer, pc, fp, /* allocation_sample*/ true);
12231191
dart_exit_stack_walker.walk();
12241192
} else {
12251193
// Fall back.
@@ -1418,9 +1386,8 @@ void Profiler::SampleThread(Thread* thread,
14181386
&counters_, (isolate != NULL) ? isolate->main_port() : ILLEGAL_PORT,
14191387
sample, sample_buffer, stack_lower, stack_upper, pc, fp, sp);
14201388
const bool exited_dart_code = thread->HasExitedDartCode();
1421-
ProfilerDartStackWalker dart_stack_walker(thread, sample, sample_buffer,
1422-
stack_lower, stack_upper, pc, fp,
1423-
sp, /* allocation_sample*/ false);
1389+
ProfilerDartStackWalker dart_stack_walker(thread, sample, sample_buffer, pc,
1390+
fp, /* allocation_sample*/ false);
14241391

14251392
// All memory access is done inside CollectSample.
14261393
CollectSample(isolate, exited_dart_code, in_dart_code, sample,

runtime/vm/simulator_dbc.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3981,11 +3981,6 @@ void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
39813981
// in the previous C++ frames.
39823982
StackResource::Unwind(thread);
39833983

3984-
// Set the tag.
3985-
thread->set_vm_tag(VMTag::kDartCompiledTagId);
3986-
// Clear top exit frame.
3987-
thread->set_top_exit_frame_info(0);
3988-
39893984
fp_ = reinterpret_cast<RawObject**>(fp);
39903985

39913986
if (pc == StubCode::RunExceptionHandler().EntryPoint()) {
@@ -4003,6 +3998,11 @@ void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
40033998
pc_ = pc;
40043999
}
40054000

4001+
// Set the tag.
4002+
thread->set_vm_tag(VMTag::kDartCompiledTagId);
4003+
// Clear top exit frame.
4004+
thread->set_top_exit_frame_info(0);
4005+
40064006
buf->Longjmp();
40074007
UNREACHABLE();
40084008
}

runtime/vm/stub_code_arm.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,7 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
938938
// R2 : arguments array.
939939
// R3 : current thread.
940940
void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
941-
// Save frame pointer coming in.
941+
__ Push(LR); // Marker for the profiler.
942942
__ EnterFrame((1 << FP) | (1 << LR), 0);
943943

944944
// Push code object to PC marker slot.
@@ -1050,6 +1050,7 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
10501050

10511051
// Restore the frame pointer and return.
10521052
__ LeaveFrame((1 << FP) | (1 << LR));
1053+
__ Drop(1);
10531054
__ Ret();
10541055
}
10551056

runtime/vm/stub_code_arm64.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,6 +1015,7 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
10151015
// Copy the C stack pointer (R31) into the stack pointer we'll actually use
10161016
// to access the stack.
10171017
__ SetupDartSP();
1018+
__ Push(LR); // Marker for the profiler.
10181019
__ EnterFrame(0);
10191020

10201021
// Push code object to PC marker slot.
@@ -1136,6 +1137,7 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
11361137

11371138
// Restore the frame pointer and C stack pointer and return.
11381139
__ LeaveFrame();
1140+
__ Drop(1);
11391141
__ RestoreCSP();
11401142
__ ret();
11411143
}
@@ -1154,6 +1156,7 @@ void StubCode::GenerateInvokeDartCodeFromBytecodeStub(Assembler* assembler) {
11541156
// Copy the C stack pointer (R31) into the stack pointer we'll actually use
11551157
// to access the stack.
11561158
__ SetupDartSP();
1159+
__ Push(LR); // Marker for the profiler.
11571160
__ EnterFrame(0);
11581161

11591162
// Push code object to PC marker slot.
@@ -1272,6 +1275,7 @@ void StubCode::GenerateInvokeDartCodeFromBytecodeStub(Assembler* assembler) {
12721275

12731276
// Restore the frame pointer and C stack pointer and return.
12741277
__ LeaveFrame();
1278+
__ Drop(1);
12751279
__ RestoreCSP();
12761280
__ ret();
12771281
#endif // defined(DART_PRECOMPILED_RUNTIME)

runtime/vm/stub_code_ia32.cc

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -732,12 +732,12 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
732732
// ESP + 16 : current thread.
733733
// Uses EAX, EDX, ECX, EDI as temporary registers.
734734
void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
735-
const intptr_t kTargetCodeOffset = 2 * kWordSize;
736-
const intptr_t kArgumentsDescOffset = 3 * kWordSize;
737-
const intptr_t kArgumentsOffset = 4 * kWordSize;
738-
const intptr_t kThreadOffset = 5 * kWordSize;
735+
const intptr_t kTargetCodeOffset = 3 * kWordSize;
736+
const intptr_t kArgumentsDescOffset = 4 * kWordSize;
737+
const intptr_t kArgumentsOffset = 5 * kWordSize;
738+
const intptr_t kThreadOffset = 6 * kWordSize;
739739

740-
// Save frame pointer coming in.
740+
__ pushl(Address(ESP, 0)); // Marker for the profiler.
741741
__ EnterFrame(0);
742742

743743
// Push code object to PC marker slot.
@@ -833,6 +833,7 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
833833

834834
// Restore the frame pointer.
835835
__ LeaveFrame();
836+
__ popl(ECX);
836837

837838
__ ret();
838839
}

runtime/vm/stub_code_x64.cc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ void StubCode::GenerateAllocateArrayStub(Assembler* assembler) {
926926
// RDX : arguments array.
927927
// RCX : current thread.
928928
void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
929-
// Save frame pointer coming in.
929+
__ pushq(Address(RSP, 0)); // Marker for the profiler.
930930
__ EnterFrame(0);
931931

932932
const Register kTargetCodeReg = CallingConventions::kArg1Reg;
@@ -1052,6 +1052,7 @@ void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) {
10521052

10531053
// Restore the frame pointer.
10541054
__ LeaveFrame();
1055+
__ popq(RCX);
10551056

10561057
__ ret();
10571058
}
@@ -1067,7 +1068,7 @@ void StubCode::GenerateInvokeDartCodeFromBytecodeStub(Assembler* assembler) {
10671068
#if defined(DART_PRECOMPILED_RUNTIME)
10681069
__ Stop("Not using interpreter");
10691070
#else
1070-
// Save frame pointer coming in.
1071+
__ pushq(Address(RSP, 0)); // Marker for the profiler.
10711072
__ EnterFrame(0);
10721073

10731074
const Register kTargetCodeReg = CallingConventions::kArg1Reg;
@@ -1193,6 +1194,7 @@ void StubCode::GenerateInvokeDartCodeFromBytecodeStub(Assembler* assembler) {
11931194

11941195
// Restore the frame pointer.
11951196
__ LeaveFrame();
1197+
__ popq(RCX);
11961198

11971199
__ ret();
11981200
#endif // defined(DART_PRECOMPILED_RUNTIME)

0 commit comments

Comments
 (0)