Skip to content

Commit e0c561c

Browse files
alexmarkovCommit Queue
authored andcommitted
[dyn_modules] Support interpreted frames in the profiler
TEST=pkg/vm_service/test Change-Id: Iba7b8e78feeff888eb0657a6e3790602a8b3d7ca Cq-Include-Trybots: luci.dart.try:vm-aot-dyn-linux-debug-x64-try,vm-aot-dyn-linux-product-x64-try,vm-dyn-linux-debug-x64-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/435240 Reviewed-by: Ryan Macnak <[email protected]> Commit-Queue: Alexander Markov <[email protected]>
1 parent 34e41dd commit e0c561c

File tree

2 files changed

+65
-16
lines changed

2 files changed

+65
-16
lines changed

runtime/vm/profiler.cc

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,7 +1035,7 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
10351035
uword* exit_fp = reinterpret_cast<uword*>(thread_->top_exit_frame_info());
10361036
bool has_exit_frame = exit_fp != nullptr;
10371037
if (has_exit_frame) {
1038-
// Exited from compiled code.
1038+
// Exited from compiled code or interpreter.
10391039
pc_ = nullptr;
10401040
fp_ = exit_fp;
10411041

@@ -1047,17 +1047,27 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
10471047
// Running compiled code.
10481048
// Use the FP and PC from the thread interrupt or simulator; already set
10491049
// in the constructor.
1050+
1051+
#if defined(DART_DYNAMIC_MODULES)
1052+
} else if (thread_->vm_tag() == VMTag::kDartInterpretedTagId) {
1053+
// Running interpreter.
1054+
pc_ = reinterpret_cast<uword*>(thread_->interpreter()->get_pc());
1055+
fp_ = reinterpret_cast<uword*>(thread_->interpreter()->get_fp());
1056+
RELEASE_ASSERT(IsInterpretedFrame());
1057+
#endif
10501058
} else {
10511059
// No Dart on the stack; caller shouldn't use this walker.
10521060
UNREACHABLE();
10531061
}
10541062

1063+
const bool is_interpreted_frame = IsInterpretedFrame();
10551064
const bool is_entry_frame =
10561065
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
1057-
StubCode::InInvocationStub(Stack(0)) ||
1058-
StubCode::InInvocationStub(Stack(1));
1066+
StubCode::InInvocationStub(Stack(0), is_interpreted_frame) ||
1067+
StubCode::InInvocationStub(Stack(1), is_interpreted_frame);
10591068
#else
1060-
StubCode::InInvocationStub(reinterpret_cast<uword>(lr_));
1069+
StubCode::InInvocationStub(reinterpret_cast<uword>(lr_),
1070+
is_interpreted_frame);
10611071
#endif
10621072
if (is_entry_frame) {
10631073
// During the prologue of a function, CallerPC will return the caller's
@@ -1075,7 +1085,8 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
10751085

10761086
for (;;) {
10771087
// Skip entry frame.
1078-
if (StubCode::InInvocationStub(reinterpret_cast<uword>(pc_))) {
1088+
if (StubCode::InInvocationStub(reinterpret_cast<uword>(pc_),
1089+
IsInterpretedFrame())) {
10791090
pc_ = nullptr;
10801091
fp_ = ExitLink();
10811092
if (fp_ == nullptr) {
@@ -1087,8 +1098,8 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
10871098
fp_ = CallerFP();
10881099

10891100
// At least one frame between exit and next entry frame.
1090-
RELEASE_ASSERT(
1091-
!StubCode::InInvocationStub(reinterpret_cast<uword>(pc_)));
1101+
RELEASE_ASSERT(!StubCode::InInvocationStub(reinterpret_cast<uword>(pc_),
1102+
IsInterpretedFrame()));
10921103
}
10931104

10941105
if (!Append(reinterpret_cast<uword>(pc_), reinterpret_cast<uword>(fp_))) {
@@ -1101,9 +1112,21 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
11011112
}
11021113

11031114
private:
1115+
bool IsInterpretedFrame() const {
1116+
#if defined(DART_DYNAMIC_MODULES)
1117+
Interpreter* interpreter = thread_->interpreter();
1118+
return (interpreter != nullptr) &&
1119+
interpreter->HasFrame(reinterpret_cast<uword>(fp_));
1120+
#else
1121+
return false;
1122+
#endif
1123+
}
1124+
11041125
uword* CallerPC() const {
11051126
ASSERT(fp_ != nullptr);
1106-
uword* caller_pc_ptr = fp_ + kSavedCallerPcSlotFromFp;
1127+
uword* caller_pc_ptr =
1128+
fp_ + (IsInterpretedFrame() ? kKBCSavedCallerPcSlotFromFp
1129+
: kSavedCallerPcSlotFromFp);
11071130
// MSan/ASan are unaware of frames initialized by generated code.
11081131
MSAN_UNPOISON(caller_pc_ptr, kWordSize);
11091132
ASAN_UNPOISON(caller_pc_ptr, kWordSize);
@@ -1112,7 +1135,9 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
11121135

11131136
uword* CallerFP() const {
11141137
ASSERT(fp_ != nullptr);
1115-
uword* caller_fp_ptr = fp_ + kSavedCallerFpSlotFromFp;
1138+
uword* caller_fp_ptr =
1139+
fp_ + (IsInterpretedFrame() ? kKBCSavedCallerFpSlotFromFp
1140+
: kSavedCallerFpSlotFromFp);
11161141
// MSan/ASan are unaware of frames initialized by generated code.
11171142
MSAN_UNPOISON(caller_fp_ptr, kWordSize);
11181143
ASAN_UNPOISON(caller_fp_ptr, kWordSize);
@@ -1121,7 +1146,9 @@ class ProfilerDartStackWalker : public ProfilerStackWalker {
11211146

11221147
uword* ExitLink() const {
11231148
ASSERT(fp_ != nullptr);
1124-
uword* exit_link_ptr = fp_ + kExitLinkSlotFromEntryFp;
1149+
uword* exit_link_ptr =
1150+
fp_ + (IsInterpretedFrame() ? kKBCExitLinkSlotFromEntryFp
1151+
: kExitLinkSlotFromEntryFp);
11251152
// MSan/ASan are unaware of frames initialized by generated code.
11261153
MSAN_UNPOISON(exit_link_ptr, kWordSize);
11271154
ASAN_UNPOISON(exit_link_ptr, kWordSize);
@@ -1503,6 +1530,8 @@ class CodeLookupTableBuilder : public ObjectVisitor {
15031530
void VisitObject(ObjectPtr raw_obj) override {
15041531
if (raw_obj->IsCode() && !Code::IsUnknownDartCode(Code::RawCast(raw_obj))) {
15051532
table_->Add(Code::Handle(Code::RawCast(raw_obj)));
1533+
} else if (raw_obj->IsBytecode()) {
1534+
table_->Add(Bytecode::Handle(Bytecode::RawCast(raw_obj)));
15061535
}
15071536
}
15081537

@@ -1555,7 +1584,7 @@ void CodeLookupTable::Build(Thread* thread) {
15551584

15561585
void CodeLookupTable::Add(const Object& code) {
15571586
ASSERT(!code.IsNull());
1558-
ASSERT(code.IsCode());
1587+
ASSERT(code.IsCode() || code.IsBytecode());
15591588
CodeDescriptor* cd = new CodeDescriptor(AbstractCode(code.ptr()));
15601589
code_objects_.Add(cd);
15611590
}
@@ -1736,6 +1765,11 @@ void ProcessedSample::CheckForMissingDartFrame(const CodeLookupTable& clt,
17361765
uword pc_marker,
17371766
uword* stack_buffer) {
17381767
ASSERT(cd != nullptr);
1768+
if (cd->code().IsBytecode()) {
1769+
// Bytecode frame build is atomic from the profiler's perspective,
1770+
// there are no missing frames.
1771+
return;
1772+
}
17391773
const Code& code = Code::Handle(Code::RawCast(cd->code().ptr()));
17401774
ASSERT(!code.IsNull());
17411775
// Some stubs (and intrinsics) do not push a frame onto the stack leaving

runtime/vm/profiler.h

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -407,20 +407,26 @@ class Sample {
407407
class AbstractCode {
408408
public:
409409
explicit AbstractCode(ObjectPtr code) : code_(Object::Handle(code)) {
410-
ASSERT(code_.IsNull() || code_.IsCode());
410+
ASSERT(code_.IsNull() || code_.IsCode() || code_.IsBytecode());
411411
}
412412

413413
ObjectPtr ptr() const { return code_.ptr(); }
414414
const Object* handle() const { return &code_; }
415415

416416
uword PayloadStart() const {
417-
ASSERT(code_.IsCode());
418-
return Code::Cast(code_).PayloadStart();
417+
if (code_.IsCode()) {
418+
return Code::Cast(code_).PayloadStart();
419+
} else {
420+
return Bytecode::Cast(code_).PayloadStart();
421+
}
419422
}
420423

421424
uword Size() const {
422-
ASSERT(code_.IsCode());
423-
return Code::Cast(code_).Size();
425+
if (code_.IsCode()) {
426+
return Code::Cast(code_).Size();
427+
} else {
428+
return Bytecode::Cast(code_).Size();
429+
}
424430
}
425431

426432
int64_t compile_timestamp() const {
@@ -434,6 +440,8 @@ class AbstractCode {
434440
const char* Name() const {
435441
if (code_.IsCode()) {
436442
return Code::Cast(code_).Name();
443+
} else if (code_.IsBytecode()) {
444+
return Bytecode::Cast(code_).Name();
437445
} else {
438446
return "";
439447
}
@@ -443,6 +451,8 @@ class AbstractCode {
443451
if (code_.IsCode()) {
444452
return Code::Cast(code_).QualifiedName(
445453
NameFormattingParams(Object::kUserVisibleName));
454+
} else if (code_.IsBytecode()) {
455+
return Bytecode::Cast(code_).QualifiedName();
446456
} else {
447457
return "";
448458
}
@@ -451,6 +461,8 @@ class AbstractCode {
451461
bool IsStubCode() const {
452462
if (code_.IsCode()) {
453463
return Code::Cast(code_).IsStubCode();
464+
} else if (code_.IsBytecode()) {
465+
return (Bytecode::Cast(code_).function() == Function::null());
454466
} else {
455467
return false;
456468
}
@@ -475,13 +487,16 @@ class AbstractCode {
475487
ObjectPtr owner() const {
476488
if (code_.IsCode()) {
477489
return Code::Cast(code_).owner();
490+
} else if (code_.IsBytecode()) {
491+
return Bytecode::Cast(code_).function();
478492
} else {
479493
return Object::null();
480494
}
481495
}
482496

483497
bool IsNull() const { return code_.IsNull(); }
484498
bool IsCode() const { return code_.IsCode(); }
499+
bool IsBytecode() const { return code_.IsBytecode(); }
485500

486501
bool is_optimized() const {
487502
if (code_.IsCode()) {

0 commit comments

Comments
 (0)