Commit 1b320d20 authored by tebbi's avatar tebbi Committed by Commit bot

[cpu-profiler] use new source position information for deoptimization in cpu profiler

The new SourcePosition class allows for precise tracking of source positions including the stack of inlinings. This CL makes the cpu profiler use this new information. Before, the cpu profiler used the deoptimization data to reconstruct the inlining stack. However, optimizing compilers (especially Turbofan) can hoist out checks such that the inlining stack of the deopt reason and the inlining stack of the position the deoptimizer jumps to can be different (the old cpu profiler tests and the ones introduced in this cl produce such situations for turbofan). In this case, relying on the deoptimization info produces paradoxical results, where the reported position is before the function responsible is called. Even worse, https://codereview.chromium.org/2451853002/ combines the precise position with the wrong inlining stack from the deopt info, leading to completely wrong results.

Other changes in this CL:
- DeoptInlinedFrame is no longer needed, because we can compute the correct inlining stack up front.
- I changed the cpu profiler tests back to test situations where deopt checks are hoisted out in Turbofan and made them robust enough to handle the differences between Crankshaft and Turbofan.
- I reversed the order of SourcePosition::InliningStack to make it match the cpu profiler convention.
- I removed CodeDeoptEvent::position, as it is no longer used.

R=alph@chromium.org

BUG=v8:5432

Review-Url: https://codereview.chromium.org/2503393002
Cr-Commit-Position: refs/heads/master@{#41168}
parent e735c5d3
......@@ -292,7 +292,7 @@ class CompilationInfo final {
inlined_code_object_root(inlined_code_object_root) {
position.position = pos;
// initialized when generating the deoptimization literals
position.inlined_function_id = -1;
position.inlined_function_id = DeoptimizationInputData::kNotInlinedIndex;
}
void RegisterInlinedFunctionId(size_t inlined_function_id) {
......
......@@ -91,8 +91,8 @@ Handle<Code> CodeGenerator::GenerateCode() {
for (CompilationInfo::InlinedFunctionHolder& inlined :
info->inlined_functions()) {
if (!inlined.shared_info.is_identical_to(info->shared_info())) {
inlined.RegisterInlinedFunctionId(deoptimization_literals_.size());
DefineDeoptimizationLiteral(inlined.shared_info);
int index = DefineDeoptimizationLiteral(inlined.shared_info);
inlined.RegisterInlinedFunctionId(index);
}
}
inlined_function_count_ = deoptimization_literals_.size();
......
......@@ -384,8 +384,8 @@ void LCodeGenBase::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
for (CompilationInfo::InlinedFunctionHolder& inlined :
info()->inlined_functions()) {
if (!inlined.shared_info.is_identical_to(info()->shared_info())) {
inlined.RegisterInlinedFunctionId(deoptimization_literals_.length());
DefineDeoptimizationLiteral(inlined.shared_info);
int index = DefineDeoptimizationLiteral(inlined.shared_info);
inlined.RegisterInlinedFunctionId(index);
}
}
inlined_function_count_ = deoptimization_literals_.length();
......
......@@ -10577,6 +10577,14 @@ Handle<DeoptimizationOutputData> DeoptimizationOutputData::New(
return Handle<DeoptimizationOutputData>::cast(result);
}
SharedFunctionInfo* DeoptimizationInputData::GetInlinedFunction(int index) {
if (index == -1) {
return SharedFunctionInfo::cast(SharedFunctionInfo());
} else {
return SharedFunctionInfo::cast(LiteralArray()->get(index));
}
}
const int LiteralsArray::kFeedbackVectorOffset =
LiteralsArray::OffsetOfElementAt(LiteralsArray::kVectorIndex);
......
......@@ -5226,6 +5226,12 @@ class DeoptimizationInputData: public FixedArray {
inline int DeoptCount();
static const int kNotInlinedIndex = -1;
// Returns the inlined function at the given position in LiteralArray, or the
// outer function if index == kNotInlinedIndex.
class SharedFunctionInfo* GetInlinedFunction(int index);
// Allocates a DeoptimizationInputData.
static Handle<DeoptimizationInputData> New(Isolate* isolate,
int deopt_entry_count,
......
......@@ -35,7 +35,7 @@ void CodeDisableOptEventRecord::UpdateCodeMap(CodeMap* code_map) {
void CodeDeoptEventRecord::UpdateCodeMap(CodeMap* code_map) {
CodeEntry* entry = code_map->FindEntry(start);
if (entry != NULL) entry->set_deopt_info(deopt_reason, position, deopt_id);
if (entry != NULL) entry->set_deopt_info(deopt_reason, deopt_id);
}
......
......@@ -83,7 +83,6 @@ class CodeDeoptEventRecord : public CodeEventRecord {
public:
Address start;
const char* deopt_reason;
SourcePosition position;
int deopt_id;
void* pc;
int fp_to_sp_delta;
......
......@@ -25,7 +25,6 @@ CodeEntry::CodeEntry(CodeEventListener::LogEventsAndTags tag, const char* name,
position_(0),
bailout_reason_(kEmptyBailoutReason),
deopt_reason_(kNoDeoptReason),
deopt_position_(SourcePosition::Unknown()),
deopt_id_(kNoDeoptimizationId),
line_info_(line_info),
instruction_start_(instruction_start) {}
......
......@@ -142,11 +142,8 @@ int CodeEntry::GetSourceLine(int pc_offset) const {
}
void CodeEntry::AddInlineStack(int pc_offset,
std::vector<CodeEntry*>& inline_stack) {
// It's better to use std::move to place the vector into the map,
// but it's not supported by the current stdlibc++ on MacOS.
inline_locations_.insert(std::make_pair(pc_offset, std::vector<CodeEntry*>()))
.first->second.swap(inline_stack);
std::vector<CodeEntry*> inline_stack) {
inline_locations_.insert(std::make_pair(pc_offset, std::move(inline_stack)));
}
const std::vector<CodeEntry*>* CodeEntry::GetInlineStack(int pc_offset) const {
......@@ -155,12 +152,9 @@ const std::vector<CodeEntry*>* CodeEntry::GetInlineStack(int pc_offset) const {
}
void CodeEntry::AddDeoptInlinedFrames(
int deopt_id, std::vector<DeoptInlinedFrame>& inlined_frames) {
// It's better to use std::move to place the vector into the map,
// but it's not supported by the current stdlibc++ on MacOS.
deopt_inlined_frames_
.insert(std::make_pair(deopt_id, std::vector<DeoptInlinedFrame>()))
.first->second.swap(inlined_frames);
int deopt_id, std::vector<CpuProfileDeoptFrame> inlined_frames) {
deopt_inlined_frames_.insert(
std::make_pair(deopt_id, std::move(inlined_frames)));
}
bool CodeEntry::HasDeoptInlinedFramesFor(int deopt_id) const {
......@@ -181,19 +175,11 @@ CpuProfileDeoptInfo CodeEntry::GetDeoptInfo() {
CpuProfileDeoptInfo info;
info.deopt_reason = deopt_reason_;
DCHECK_NE(kNoDeoptimizationId, deopt_id_);
size_t position = static_cast<size_t>(deopt_position_.ScriptOffset());
if (deopt_inlined_frames_.find(deopt_id_) == deopt_inlined_frames_.end()) {
info.stack.push_back(CpuProfileDeoptFrame({script_id_, position}));
info.stack.push_back(CpuProfileDeoptFrame(
{script_id_, static_cast<size_t>(std::max(0, position()))}));
} else {
// Copy stack of inlined frames where the deopt happened.
std::vector<DeoptInlinedFrame>& frames = deopt_inlined_frames_[deopt_id_];
bool first = true;
for (DeoptInlinedFrame& inlined_frame : base::Reversed(frames)) {
info.stack.push_back(
CpuProfileDeoptFrame({inlined_frame.script_id,
first ? position : inlined_frame.position}));
first = false; // Done with innermost frame.
}
info.stack = deopt_inlined_frames_[deopt_id_];
}
return info;
}
......
......@@ -49,13 +49,6 @@ class CodeEntry {
Address instruction_start = NULL);
~CodeEntry();
// Container describing inlined frames at eager deopt points. Is eventually
// being translated into v8::CpuProfileDeoptFrame by the profiler.
struct DeoptInlinedFrame {
int position;
int script_id;
};
const char* name_prefix() const { return name_prefix_; }
bool has_name_prefix() const { return name_prefix_[0] != '\0'; }
const char* name() const { return name_; }
......@@ -72,18 +65,15 @@ class CodeEntry {
}
const char* bailout_reason() const { return bailout_reason_; }
void set_deopt_info(const char* deopt_reason, SourcePosition position,
int deopt_id) {
void set_deopt_info(const char* deopt_reason, int deopt_id) {
DCHECK(!has_deopt_info());
deopt_reason_ = deopt_reason;
deopt_position_ = position;
deopt_id_ = deopt_id;
}
CpuProfileDeoptInfo GetDeoptInfo();
bool has_deopt_info() const { return deopt_id_ != kNoDeoptimizationId; }
void clear_deopt_info() {
deopt_reason_ = kNoDeoptReason;
deopt_position_ = SourcePosition::Unknown();
deopt_id_ = kNoDeoptimizationId;
}
......@@ -99,10 +89,10 @@ class CodeEntry {
int GetSourceLine(int pc_offset) const;
void AddInlineStack(int pc_offset, std::vector<CodeEntry*>& inline_stack);
void AddInlineStack(int pc_offset, std::vector<CodeEntry*> inline_stack);
const std::vector<CodeEntry*>* GetInlineStack(int pc_offset) const;
void AddDeoptInlinedFrames(int deopt_id, std::vector<DeoptInlinedFrame>&);
void AddDeoptInlinedFrames(int deopt_id, std::vector<CpuProfileDeoptFrame>);
bool HasDeoptInlinedFramesFor(int deopt_id) const;
Address instruction_start() const { return instruction_start_; }
......@@ -167,13 +157,12 @@ class CodeEntry {
int position_;
const char* bailout_reason_;
const char* deopt_reason_;
SourcePosition deopt_position_;
int deopt_id_;
JITLineInfoTable* line_info_;
Address instruction_start_;
// Should be an unordered_map, but it doesn't currently work on Win & MacOS.
std::map<int, std::vector<CodeEntry*>> inline_locations_;
std::map<int, std::vector<DeoptInlinedFrame>> deopt_inlined_frames_;
std::map<int, std::vector<CpuProfileDeoptFrame>> deopt_inlined_frames_;
DISALLOW_COPY_AND_ASSIGN(CodeEntry);
};
......
......@@ -90,18 +90,13 @@ void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag,
line_table = new JITLineInfoTable();
int offset = abstract_code->IsCode() ? Code::kHeaderSize
: BytecodeArray::kHeaderSize;
int start_position = shared->start_position();
int end_position = shared->end_position();
for (SourcePositionTableIterator it(abstract_code->source_position_table());
!it.done(); it.Advance()) {
// TODO(alph,tebbi) Skipping inlined positions for now, because they might
// refer to a different script.
if (it.source_position().InliningId() != SourcePosition::kNotInlined)
continue;
int position = it.source_position().ScriptOffset();
// TODO(alph): in case of inlining the position may correspond to an
// inlined function source code. Do not collect positions that fall
// beyond the function source code. There's however a chance the
// inlined function has similar positions but in another script. So
// the proper fix is to store script_id in some form along with the
// inlined function positions.
if (position < start_position || position >= end_position) continue;
int line_number = script->GetLineNumber(position) + 1;
int pc_offset = it.code_offset() + offset;
line_table->SetPosition(pc_offset, line_number);
......@@ -156,7 +151,6 @@ void ProfilerListener::CodeDeoptEvent(Code* code, Address pc,
Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc);
rec->start = code->address();
rec->deopt_reason = DeoptimizeReasonToString(info.deopt_reason);
rec->position = info.position;
rec->deopt_id = info.deopt_id;
rec->pc = reinterpret_cast<void*>(pc);
rec->fp_to_sp_delta = fp_to_sp_delta;
......@@ -245,8 +239,7 @@ void ProfilerListener::RecordInliningInfo(CodeEntry* entry,
inline_stack.push_back(inline_entry);
}
if (!inline_stack.empty()) {
entry->AddInlineStack(pc_offset, inline_stack);
DCHECK(inline_stack.empty());
entry->AddInlineStack(pc_offset, std::move(inline_stack));
}
}
}
......@@ -254,55 +247,36 @@ void ProfilerListener::RecordInliningInfo(CodeEntry* entry,
void ProfilerListener::RecordDeoptInlinedFrames(CodeEntry* entry,
AbstractCode* abstract_code) {
if (abstract_code->kind() != AbstractCode::OPTIMIZED_FUNCTION) return;
Code* code = abstract_code->GetCode();
DeoptimizationInputData* deopt_input_data =
DeoptimizationInputData::cast(code->deoptimization_data());
int const mask = RelocInfo::ModeMask(RelocInfo::DEOPT_ID);
for (RelocIterator rit(code, mask); !rit.done(); rit.next()) {
RelocInfo* reloc_info = rit.rinfo();
DCHECK(RelocInfo::IsDeoptId(reloc_info->rmode()));
int deopt_id = static_cast<int>(reloc_info->data());
int translation_index =
deopt_input_data->TranslationIndex(deopt_id)->value();
TranslationIterator it(deopt_input_data->TranslationByteArray(),
translation_index);
Translation::Opcode opcode = static_cast<Translation::Opcode>(it.Next());
DCHECK_EQ(Translation::BEGIN, opcode);
it.Skip(Translation::NumberOfOperandsFor(opcode));
std::vector<CodeEntry::DeoptInlinedFrame> inlined_frames;
while (it.HasNext() &&
Translation::BEGIN !=
(opcode = static_cast<Translation::Opcode>(it.Next()))) {
if (opcode != Translation::JS_FRAME &&
opcode != Translation::INTERPRETED_FRAME) {
it.Skip(Translation::NumberOfOperandsFor(opcode));
continue;
}
BailoutId ast_id = BailoutId(it.Next());
int shared_info_id = it.Next();
it.Next(); // Skip height
SharedFunctionInfo* shared = SharedFunctionInfo::cast(
deopt_input_data->LiteralArray()->get(shared_info_id));
int source_position;
if (opcode == Translation::INTERPRETED_FRAME) {
source_position =
Deoptimizer::ComputeSourcePositionFromBytecodeArray(shared, ast_id);
} else {
DCHECK(opcode == Translation::JS_FRAME);
source_position =
Deoptimizer::ComputeSourcePositionFromBaselineCode(shared, ast_id);
Handle<Code> code(abstract_code->GetCode());
SourcePosition last_position = SourcePosition::Unknown();
int mask = RelocInfo::ModeMask(RelocInfo::DEOPT_ID) |
RelocInfo::ModeMask(RelocInfo::DEOPT_SCRIPT_OFFSET) |
RelocInfo::ModeMask(RelocInfo::DEOPT_INLINING_ID);
for (RelocIterator it(*code, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
if (info->rmode() == RelocInfo::DEOPT_SCRIPT_OFFSET) {
int script_offset = static_cast<int>(info->data());
it.next();
DCHECK(it.rinfo()->rmode() == RelocInfo::DEOPT_INLINING_ID);
int inlining_id = static_cast<int>(it.rinfo()->data());
last_position = SourcePosition(script_offset, inlining_id);
continue;
}
if (info->rmode() == RelocInfo::DEOPT_ID) {
int deopt_id = static_cast<int>(info->data());
DCHECK(last_position.IsKnown());
std::vector<CpuProfileDeoptFrame> inlined_frames;
for (SourcePositionInfo& pos_info : last_position.InliningStack(code)) {
DCHECK(pos_info.position.ScriptOffset() != kNoSourcePosition);
size_t offset = static_cast<size_t>(pos_info.position.ScriptOffset());
int script_id = Script::cast(pos_info.function->script())->id();
inlined_frames.push_back(CpuProfileDeoptFrame({script_id, offset}));
}
int script_id = v8::UnboundScript::kNoScriptId;
if (shared->script()->IsScript()) {
Script* script = Script::cast(shared->script());
script_id = script->id();
if (!inlined_frames.empty() &&
!entry->HasDeoptInlinedFramesFor(deopt_id)) {
entry->AddDeoptInlinedFrames(deopt_id, std::move(inlined_frames));
}
CodeEntry::DeoptInlinedFrame frame = {source_position, script_id};
inlined_frames.push_back(frame);
}
if (!inlined_frames.empty() && !entry->HasDeoptInlinedFramesFor(deopt_id)) {
entry->AddDeoptInlinedFrames(deopt_id, inlined_frames);
DCHECK(inlined_frames.empty());
}
}
}
......
......@@ -10,28 +10,25 @@ namespace v8 {
namespace internal {
std::ostream& operator<<(std::ostream& out, const SourcePositionInfo& pos) {
Handle<SharedFunctionInfo> function;
if (pos.function.ToHandle(&function)) {
Handle<Script> script(Script::cast(function->script()));
out << "<";
if (script->name()->IsString()) {
out << String::cast(script->name())->ToCString(DISALLOW_NULLS).get();
} else {
out << "unknown";
}
out << ":" << pos.line + 1 << ":" << pos.column + 1 << ">";
Handle<SharedFunctionInfo> function(pos.function);
Handle<Script> script(Script::cast(function->script()));
out << "<";
if (script->name()->IsString()) {
out << String::cast(script->name())->ToCString(DISALLOW_NULLS).get();
} else {
out << "<unknown:" << pos.position.ScriptOffset() << ">";
out << "unknown";
}
out << ":" << pos.line + 1 << ":" << pos.column + 1 << ">";
return out;
}
std::ostream& operator<<(std::ostream& out,
const std::vector<SourcePositionInfo>& stack) {
out << stack.back();
for (int i = static_cast<int>(stack.size()) - 2; i >= 0; --i) {
out << " inlined at ";
out << stack[i];
bool first = true;
for (const SourcePositionInfo& pos : stack) {
if (!first) out << " inlined at ";
out << pos;
first = false;
}
return out;
}
......@@ -48,51 +45,48 @@ std::ostream& operator<<(std::ostream& out, const SourcePosition& pos) {
SourcePositionInfo SourcePosition::Info(
Handle<SharedFunctionInfo> function) const {
SourcePositionInfo result(*this, function);
Handle<Script> script(Script::cast(function->script()));
SourcePositionInfo result(*this);
Script::PositionInfo pos;
if (Script::GetPositionInfo(script, ScriptOffset(), &pos,
Script::WITH_OFFSET)) {
result.line = pos.line;
result.column = pos.column;
}
result.function = function;
return result;
}
std::vector<SourcePositionInfo> SourcePosition::InliningStack(
CompilationInfo* cinfo) const {
if (!isInlined()) {
return std::vector<SourcePositionInfo>{Info(cinfo->shared_info())};
} else {
InliningPosition inl = cinfo->inlined_functions()[InliningId()].position;
std::vector<SourcePositionInfo> stack = inl.position.InliningStack(cinfo);
stack.push_back(Info(cinfo->inlined_functions()[InliningId()].shared_info));
return stack;
SourcePosition pos = *this;
std::vector<SourcePositionInfo> stack;
while (pos.isInlined()) {
const auto& inl = cinfo->inlined_functions()[pos.InliningId()];
stack.push_back(pos.Info(inl.shared_info));
pos = inl.position.position;
}
stack.push_back(pos.Info(cinfo->shared_info()));
return stack;
}
std::vector<SourcePositionInfo> SourcePosition::InliningStack(
Handle<Code> code) const {
Handle<DeoptimizationInputData> deopt_data(
DeoptimizationInputData::cast(code->deoptimization_data()));
if (!isInlined()) {
SourcePosition pos = *this;
std::vector<SourcePositionInfo> stack;
while (pos.isInlined()) {
InliningPosition inl =
deopt_data->InliningPositions()->get(pos.InliningId());
Handle<SharedFunctionInfo> function(
SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo()));
return std::vector<SourcePositionInfo>{Info(function)};
} else {
InliningPosition inl = deopt_data->InliningPositions()->get(InliningId());
std::vector<SourcePositionInfo> stack = inl.position.InliningStack(code);
if (inl.inlined_function_id == -1) {
stack.push_back(SourcePositionInfo(*this));
} else {
Handle<SharedFunctionInfo> function(SharedFunctionInfo::cast(
deopt_data->LiteralArray()->get(inl.inlined_function_id)));
stack.push_back(Info(function));
}
return stack;
deopt_data->GetInlinedFunction(inl.inlined_function_id));
stack.push_back(pos.Info(function));
pos = inl.position;
}
Handle<SharedFunctionInfo> function(
SharedFunctionInfo::cast(deopt_data->SharedFunctionInfo()));
stack.push_back(pos.Info(function));
return stack;
}
void SourcePosition::Print(std::ostream& out,
......@@ -124,8 +118,8 @@ void SourcePosition::Print(std::ostream& out, Code* code) const {
if (inl.inlined_function_id == -1) {
out << *this;
} else {
SharedFunctionInfo* function = SharedFunctionInfo::cast(
deopt_data->LiteralArray()->get(inl.inlined_function_id));
SharedFunctionInfo* function =
deopt_data->GetInlinedFunction(inl.inlined_function_id);
Print(out, function);
}
out << " inlined at ";
......
......@@ -67,17 +67,13 @@ class SourcePosition final {
int64_t raw() const { return static_cast<int64_t>(value_); }
static SourcePosition FromRaw(int64_t raw) {
SourcePosition position;
SourcePosition position = Unknown();
DCHECK_GE(raw, 0);
position.value_ = static_cast<uint64_t>(raw);
return position;
}
private:
// SourcePosition is used in a union in CodeEventsContainer, which requires a
// trivial constructor.
SourcePosition() = default;
void Print(std::ostream& out, SharedFunctionInfo* function) const;
SourcePositionInfo Info(Handle<SharedFunctionInfo> script) const;
......@@ -106,10 +102,11 @@ struct InliningPosition {
};
struct SourcePositionInfo {
explicit SourcePositionInfo(SourcePosition pos) : position(pos) {}
explicit SourcePositionInfo(SourcePosition pos, Handle<SharedFunctionInfo> f)
: position(pos), function(f) {}
SourcePosition position;
MaybeHandle<SharedFunctionInfo> function;
Handle<SharedFunctionInfo> function;
int line = -1;
int column = -1;
};
......
......@@ -66,6 +66,11 @@ static size_t offset(const char* src, const char* substring) {
return static_cast<size_t>(it - src);
}
template <typename A, typename B>
static int dist(A a, B b) {
return abs(static_cast<int>(a) - static_cast<int>(b));
}
static const char* reason(const i::DeoptimizeReason reason) {
return i::DeoptimizeReasonToString(reason);
}
......@@ -1906,7 +1911,8 @@ TEST(SourceLocation) {
}
static const char* inlined_source =
"function opt_function(f) { return f()*f(); }\n";
"function opt_function(left, right) { var k = left*right; return k + 1; "
"}\n";
// 0.........1.........2.........3.........4....*....5.........6......*..7
......@@ -1923,16 +1929,17 @@ TEST(DeoptAtFirstLevelInlinedSource) {
// 0.........1.........2.........3.........4.........5.........6.........7
const char* source =
"function test(f) { return opt_function(f); }\n"
"function test(left, right) { return opt_function(left, right); }\n"
"\n"
"startProfiling();\n"
"\n"
"test(function(){return 10});test(function(){return 12});\n"
"test(10, 10);\n"
"\n"
"%SetForceInlineFlag(opt_function);\n"
"%OptimizeFunctionOnNextCall(test)\n"
"\n"
"test(function(){return 100000000000});\n"
"test(10, 10);\n"
"\n"
"test(undefined, 1e9);\n"
"\n"
"stopProfiling();\n"
"\n";
......@@ -1967,13 +1974,13 @@ TEST(DeoptAtFirstLevelInlinedSource) {
CHECK_EQ(1U, deopt_infos.size());
const v8::CpuProfileDeoptInfo& info = deopt_infos[0];
CHECK_EQ(reason(i::DeoptimizeReason::kNotASmi), info.deopt_reason);
CHECK(reason(i::DeoptimizeReason::kNotASmi) == info.deopt_reason ||
reason(i::DeoptimizeReason::kNotAHeapNumber) == info.deopt_reason);
CHECK_EQ(2U, info.stack.size());
CHECK_EQ(inlined_script_id, info.stack[0].script_id);
CHECK(abs(static_cast<int>(offset(inlined_source, "*f()")) -
static_cast<int>(info.stack[0].position)) <= 1);
CHECK_LE(dist(offset(inlined_source, "*right"), info.stack[0].position), 1);
CHECK_EQ(script_id, info.stack[1].script_id);
CHECK_EQ(offset(source, "opt_function(f)"), info.stack[1].position);
CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position);
iprofiler->DeleteProfile(iprofile);
}
......@@ -1992,21 +1999,18 @@ TEST(DeoptAtSecondLevelInlinedSource) {
// 0.........1.........2.........3.........4.........5.........6.........7
const char* source =
"function test2(f) { return opt_function(f); }\n"
"function test1(f) { return test2(f); }\n"
"function test2(left, right) { return opt_function(left, right); }\n"
"function test1(left, right) { return test2(left, right); } \n"
"\n"
"startProfiling();\n"
"\n"
"test1(function(){return 10});\n"
"test1(function(){return 11});\n"
"test1(10, 10);\n"
"\n"
"%SetForceInlineFlag(test2);\n"
"%SetForceInlineFlag(opt_function);\n"
"%OptimizeFunctionOnNextCall(test1)\n"
"\n"
"test1(function(){return 12});\n"
"test1(10, 10);\n"
"\n"
"test1(function(){return 100000000000});\n"
"test1(undefined, 1e9);\n"
"\n"
"stopProfiling();\n"
"\n";
......@@ -2044,14 +2048,14 @@ TEST(DeoptAtSecondLevelInlinedSource) {
CHECK_EQ(1U, deopt_infos.size());
const v8::CpuProfileDeoptInfo info = deopt_infos[0];
CHECK_EQ(reason(i::DeoptimizeReason::kNotASmi), info.deopt_reason);
CHECK(reason(i::DeoptimizeReason::kNotASmi) == info.deopt_reason ||
reason(i::DeoptimizeReason::kNotAHeapNumber) == info.deopt_reason);
CHECK_EQ(3U, info.stack.size());
CHECK_EQ(inlined_script_id, info.stack[0].script_id);
CHECK(abs(static_cast<int>(offset(inlined_source, "*f()")) -
static_cast<int>(info.stack[0].position)) <= 1);
CHECK_LE(dist(offset(inlined_source, "*right"), info.stack[0].position), 1);
CHECK_EQ(script_id, info.stack[1].script_id);
CHECK_EQ(offset(source, "opt_function(f)"), info.stack[1].position);
CHECK_EQ(offset(source, "test2(f);"), info.stack[2].position);
CHECK_EQ(offset(source, "opt_function(left,"), info.stack[1].position);
CHECK_EQ(offset(source, "test2(left, right);"), info.stack[2].position);
iprofiler->DeleteProfile(iprofile);
}
......@@ -2072,17 +2076,15 @@ TEST(DeoptUntrackedFunction) {
const char* source =
"function test(left, right) { return opt_function(left, right); }\n"
"\n"
"test(function(){return 10});\n"
"test(function(){return 11});\n"
"test(10, 10);\n"
"\n"
"%SetForceInlineFlag(opt_function);\n"
"%OptimizeFunctionOnNextCall(test)\n"
"\n"
"test(function(){return 10});\n"
"test(10, 10);\n"
"\n"
"startProfiling();\n" // profiler started after compilation.
"\n"
"test(function(){return 100000000000});\n"
"test(undefined, 10);\n"
"\n"
"stopProfiling();\n"
"\n";
......
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