Commit 66ab309e authored by loislo's avatar loislo Committed by Commit bot

CpuProfiler: fix for GetDeoptReason code.

The original code always returned the first entry from RelocInfo that matched with
bailout_id. But we may have a few different deopt reasons for one bailout_id.
So we need to get the one which matches with a particular call from JumpTable.

We can do this by checking not 'target_address' (it maps to bailout_id)
but 'from' address which maps to a particular JumpTable entry.

The test was reworked so it tests identical functions against different reasons.

BUG=chromium:452067
LOG=n

Review URL: https://codereview.chromium.org/984773003

Cr-Commit-Position: refs/heads/master@{#27076}
parent 4a709dd6
......@@ -329,11 +329,10 @@ void CpuProfiler::CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared) {
}
void CpuProfiler::CodeDeoptEvent(Code* code, int bailout_id, Address pc,
int fp_to_sp_delta) {
void CpuProfiler::CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) {
CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT);
CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_;
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, bailout_id);
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
rec->start = code->address();
rec->deopt_reason = Deoptimizer::GetDeoptReason(info.deopt_reason);
rec->position = info.position;
......
......@@ -235,8 +235,7 @@ class CpuProfiler : public CodeEventListener {
virtual void CodeMovingGCEvent() {}
virtual void CodeMoveEvent(Address from, Address to);
virtual void CodeDisableOptEvent(Code* code, SharedFunctionInfo* shared);
virtual void CodeDeoptEvent(Code* code, int bailout_id, Address pc,
int fp_to_sp_delta);
virtual void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta);
virtual void CodeDeleteEvent(Address from);
virtual void GetterCallbackEvent(Name* name, Address entry_point);
virtual void RegExpCodeCreateEvent(Code* code, String* source);
......
......@@ -610,8 +610,7 @@ Deoptimizer::Deoptimizer(Isolate* isolate,
disallow_heap_allocation_ = new DisallowHeapAllocation();
#endif // DEBUG
if (compiled_code_->kind() == Code::OPTIMIZED_FUNCTION) {
PROFILE(isolate_, CodeDeoptEvent(compiled_code_, bailout_id_, from_,
fp_to_sp_delta_));
PROFILE(isolate_, CodeDeoptEvent(compiled_code_, from_, fp_to_sp_delta_));
}
unsigned size = ComputeInputFrameSize();
input_ = new(size) FrameDescription(size, function);
......@@ -770,7 +769,7 @@ void Deoptimizer::DoComputeOutputFrames() {
fp_to_sp_delta_);
if (bailout_type_ == EAGER || bailout_type_ == SOFT ||
(compiled_code_->is_hydrogen_stub())) {
compiled_code_->PrintDeoptLocation(trace_scope_->file(), bailout_id_);
compiled_code_->PrintDeoptLocation(trace_scope_->file(), from_);
}
}
......@@ -3649,34 +3648,20 @@ const char* Deoptimizer::GetDeoptReason(DeoptReason deopt_reason) {
}
Deoptimizer::DeoptInfo Deoptimizer::GetDeoptInfo(Code* code, int bailout_id) {
Deoptimizer::DeoptInfo Deoptimizer::GetDeoptInfo(Code* code, Address pc) {
SourcePosition last_position = SourcePosition::Unknown();
Isolate* isolate = code->GetIsolate();
Deoptimizer::DeoptReason last_reason = Deoptimizer::kNoReason;
int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_REASON) |
RelocInfo::ModeMask(RelocInfo::POSITION) |
RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY);
RelocInfo::ModeMask(RelocInfo::POSITION);
for (RelocIterator it(code, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
if (info->pc() >= pc) return DeoptInfo(last_position, NULL, last_reason);
if (info->rmode() == RelocInfo::POSITION) {
int raw_position = static_cast<int>(info->data());
last_position = raw_position ? SourcePosition::FromRaw(raw_position)
: SourcePosition::Unknown();
} else if (info->rmode() == RelocInfo::DEOPT_REASON) {
last_reason = static_cast<Deoptimizer::DeoptReason>(info->data());
} else if (last_reason != Deoptimizer::kNoReason) {
if ((bailout_id ==
Deoptimizer::GetDeoptimizationId(isolate, info->target_address(),
Deoptimizer::EAGER)) ||
(bailout_id ==
Deoptimizer::GetDeoptimizationId(isolate, info->target_address(),
Deoptimizer::SOFT)) ||
(bailout_id ==
Deoptimizer::GetDeoptimizationId(isolate, info->target_address(),
Deoptimizer::LAZY))) {
CHECK(RelocInfo::IsRuntimeEntry(info->rmode()));
return DeoptInfo(last_position, NULL, last_reason);
}
}
}
return DeoptInfo(SourcePosition::Unknown(), NULL, Deoptimizer::kNoReason);
......
......@@ -192,7 +192,7 @@ class Deoptimizer : public Malloced {
DeoptReason deopt_reason;
};
static DeoptInfo GetDeoptInfo(Code* code, int bailout_id);
static DeoptInfo GetDeoptInfo(Code* code, byte* from);
struct JumpTableEntry : public ZoneObject {
inline JumpTableEntry(Address entry, const DeoptInfo& deopt_info,
......
......@@ -893,9 +893,8 @@ void Logger::SharedLibraryEvent(const std::string& library_path,
}
void Logger::CodeDeoptEvent(Code* code, int bailout_id, Address from,
int fp_to_sp_delta) {
PROFILER_LOG(CodeDeoptEvent(code, bailout_id, from, fp_to_sp_delta));
void Logger::CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) {
PROFILER_LOG(CodeDeoptEvent(code, pc, fp_to_sp_delta));
if (!log_->IsEnabled() || !FLAG_log_internal_timer_events) return;
Log::MessageBuilder msg(log_);
int since_epoch = static_cast<int>(timer_.Elapsed().InMicroseconds());
......
......@@ -291,8 +291,7 @@ class Logger {
uintptr_t start,
uintptr_t end);
void CodeDeoptEvent(Code* code, int bailout_id, Address from,
int fp_to_sp_delta);
void CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta);
void CurrentTimeEvent();
void TimerEvent(StartEnd se, const char* name);
......
......@@ -11238,8 +11238,8 @@ Code* Code::GetCodeAgeStub(Isolate* isolate, Age age, MarkingParity parity) {
}
void Code::PrintDeoptLocation(FILE* out, int bailout_id) {
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, bailout_id);
void Code::PrintDeoptLocation(FILE* out, Address pc) {
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(this, pc);
class SourcePosition pos = info.position;
if (info.deopt_reason != Deoptimizer::kNoReason || !pos.IsUnknown()) {
if (FLAG_hydrogen_track_positions) {
......
......@@ -5417,7 +5417,7 @@ class Code: public HeapObject {
return GetCodeAgeStub(isolate, kNotExecutedCodeAge, NO_MARKING_PARITY);
}
void PrintDeoptLocation(FILE* out, int bailout_id);
void PrintDeoptLocation(FILE* out, Address pc);
bool CanDeoptAt(Address pc);
#ifdef VERIFY_HEAP
......
......@@ -1696,6 +1696,16 @@ TEST(DontStopOnFinishedProfileDelete) {
}
const char* GetBranchDeoptReason(i::CpuProfile* iprofile, const char* branch[],
int length) {
v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
const ProfileNode* iopt_function = NULL;
iopt_function = GetSimpleBranch(profile, branch, length);
CHECK_EQ(1, iopt_function->deopt_infos().length());
return iopt_function->deopt_infos()[0].deopt_reason;
}
// deopt at top function
TEST(CollectDeoptEvents) {
if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
......@@ -1707,34 +1717,46 @@ TEST(CollectDeoptEvents) {
v8::CpuProfiler* profiler = isolate->GetCpuProfiler();
i::CpuProfiler* iprofiler = reinterpret_cast<i::CpuProfiler*>(profiler);
const char* source =
"function opt_function(left, right, depth) {\n"
" if (depth) return opt_function(left, right, depth - 1);\n"
const char opt_source[] =
"function opt_function%d(value, depth) {\n"
" if (depth) return opt_function%d(value, depth - 1);\n"
"\n"
" var k = left / 10;\n"
" var r = 10 / right;\n"
" return k + r;"
" return 10 / value;\n"
"}\n"
"\n";
for (int i = 0; i < 3; ++i) {
i::EmbeddedVector<char, sizeof(opt_source) + 100> buffer;
i::SNPrintF(buffer, opt_source, i, i);
v8::Script::Compile(v8_str(buffer.start()))->Run();
}
const char* source =
"startProfiling();\n"
"\n"
"function test(left, right) {\n"
" return opt_function(left, right, 1);\n"
"}\n"
"opt_function0(1, 1);\n"
"\n"
"startProfiling();\n"
"%OptimizeFunctionOnNextCall(opt_function0)\n"
"\n"
"opt_function0(1, 1);\n"
"\n"
"opt_function0(undefined, 1);\n"
"\n"
"test(10, 10);\n"
"opt_function1(1, 1);\n"
"\n"
"%OptimizeFunctionOnNextCall(opt_function)\n"
"%OptimizeFunctionOnNextCall(opt_function1)\n"
"\n"
"test(10, 10);\n"
"opt_function1(1, 1);\n"
"\n"
"test(undefined, 10);\n"
"opt_function1(NaN, 1);\n"
"\n"
"%OptimizeFunctionOnNextCall(opt_function)\n"
"opt_function2(1, 1);\n"
"\n"
"test(10, 10);\n"
"%OptimizeFunctionOnNextCall(opt_function2)\n"
"\n"
"test(10, 0);\n"
"opt_function2(1, 1);\n"
"\n"
"opt_function2(0, 1);\n"
"\n"
"stopProfiling();\n"
"\n";
......@@ -1742,15 +1764,21 @@ TEST(CollectDeoptEvents) {
v8::Script::Compile(v8_str(source))->Run();
i::CpuProfile* iprofile = iprofiler->GetProfile(0);
iprofile->Print();
v8::CpuProfile* profile = reinterpret_cast<v8::CpuProfile*>(iprofile);
const char* branch[] = {"", "test", "opt_function", "opt_function"};
const ProfileNode* iopt_function =
GetSimpleBranch(profile, branch, arraysize(branch));
CHECK_EQ(2, iopt_function->deopt_infos().length());
CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber),
iopt_function->deopt_infos()[0].deopt_reason);
CHECK_EQ(reason(i::Deoptimizer::kDivisionByZero),
iopt_function->deopt_infos()[1].deopt_reason);
{
const char* branch[] = {"", "opt_function0", "opt_function0"};
CHECK_EQ(reason(i::Deoptimizer::kNotAHeapNumber),
GetBranchDeoptReason(iprofile, branch, arraysize(branch)));
}
{
const char* branch[] = {"", "opt_function1", "opt_function1"};
CHECK_EQ(reason(i::Deoptimizer::kNaN),
GetBranchDeoptReason(iprofile, branch, arraysize(branch)));
}
{
const char* branch[] = {"", "opt_function2", "opt_function2"};
CHECK_EQ(reason(i::Deoptimizer::kDivisionByZero),
GetBranchDeoptReason(iprofile, branch, arraysize(branch)));
}
iprofiler->DeleteProfile(iprofile);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment