[coverage] Use shared_ptr instead of raw pointer

If Coverage goes out of scope, ScriptData, FunctionData, or BlockData still rely on 
Coverage's coverage_. Make coverage_ a shared_ptr owned by all four classes. 

Bug: 
Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: Ifab5d05184cc5db0fd0a935254b967286295e63f
Reviewed-on: https://chromium-review.googlesource.com/657381
Reviewed-by: Yang Guo <yangguo@chromium.org>
Commit-Queue: Franziska Hinkelmann <franzih@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47938}
This commit is contained in:
Franziska Hinkelmann 2017-09-09 19:14:57 +02:00 committed by Commit Bot
parent 0921c6c3b1
commit 50fb877eb8
6 changed files with 136 additions and 23 deletions

View File

@ -10167,7 +10167,7 @@ bool debug::Coverage::FunctionData::HasBlockCoverage() const {
debug::Coverage::BlockData debug::Coverage::FunctionData::GetBlockData(
size_t i) const {
return BlockData(&function_->blocks.at(i));
return BlockData(&function_->blocks.at(i), coverage_);
}
Local<debug::Script> debug::Coverage::ScriptData::GetScript() const {
@ -10180,15 +10180,20 @@ size_t debug::Coverage::ScriptData::FunctionCount() const {
debug::Coverage::FunctionData debug::Coverage::ScriptData::GetFunctionData(
size_t i) const {
return FunctionData(&script_->functions.at(i));
return FunctionData(&script_->functions.at(i), coverage_);
}
debug::Coverage::~Coverage() { delete coverage_; }
debug::Coverage::Coverage(std::shared_ptr<i::Coverage> coverage)
: coverage_(std::move(coverage)) {}
debug::Coverage::ScriptData::ScriptData(size_t index,
std::shared_ptr<i::Coverage> coverage)
: script_(&coverage->at(index)), coverage_(std::move(coverage)) {}
size_t debug::Coverage::ScriptCount() const { return coverage_->size(); }
debug::Coverage::ScriptData debug::Coverage::GetScriptData(size_t i) const {
return ScriptData(&coverage_->at(i));
return ScriptData(i, coverage_);
}
debug::Coverage debug::Coverage::CollectPrecise(Isolate* isolate) {

View File

@ -380,9 +380,10 @@ void CollectBlockCoverage(Isolate* isolate, CoverageFunction* function,
}
} // anonymous namespace
Coverage* Coverage::CollectPrecise(Isolate* isolate) {
std::unique_ptr<Coverage> Coverage::CollectPrecise(Isolate* isolate) {
DCHECK(!isolate->is_best_effort_code_coverage());
Coverage* result = Collect(isolate, isolate->code_coverage_mode());
std::unique_ptr<Coverage> result =
Collect(isolate, isolate->code_coverage_mode());
if (isolate->is_precise_binary_code_coverage() ||
isolate->is_block_binary_code_coverage()) {
// We do not have to hold onto feedback vectors for invocations we already
@ -392,12 +393,12 @@ Coverage* Coverage::CollectPrecise(Isolate* isolate) {
return result;
}
Coverage* Coverage::CollectBestEffort(Isolate* isolate) {
std::unique_ptr<Coverage> Coverage::CollectBestEffort(Isolate* isolate) {
return Collect(isolate, v8::debug::Coverage::kBestEffort);
}
Coverage* Coverage::Collect(Isolate* isolate,
v8::debug::Coverage::Mode collectionMode) {
std::unique_ptr<Coverage> Coverage::Collect(
Isolate* isolate, v8::debug::Coverage::Mode collectionMode) {
SharedToCounterMap counter_map;
const bool reset_count = collectionMode != v8::debug::Coverage::kBestEffort;
@ -439,7 +440,7 @@ Coverage* Coverage::Collect(Isolate* isolate,
// Iterate shared function infos of every script and build a mapping
// between source ranges and invocation counts.
Coverage* result = new Coverage();
std::unique_ptr<Coverage> result(new Coverage());
Script::Iterator scripts(isolate);
while (Script* script = scripts.Next()) {
if (!script->IsUserJavaScript()) continue;

View File

@ -51,17 +51,17 @@ class Coverage : public std::vector<CoverageScript> {
// In case of kPreciseCount, an updated count since last collection is
// returned. In case of kPreciseBinary, a count of 1 is returned if a
// function has been executed for the first time since last collection.
static Coverage* CollectPrecise(Isolate* isolate);
static std::unique_ptr<Coverage> CollectPrecise(Isolate* isolate);
// Collecting best effort coverage always works, but may be imprecise
// depending on selected mode. The invocation count is not reset.
static Coverage* CollectBestEffort(Isolate* isolate);
static std::unique_ptr<Coverage> CollectBestEffort(Isolate* isolate);
// Select code coverage mode.
static void SelectMode(Isolate* isolate, debug::Coverage::Mode mode);
private:
static Coverage* Collect(Isolate* isolate,
v8::debug::Coverage::Mode collectionMode);
static std::unique_ptr<Coverage> Collect(
Isolate* isolate, v8::debug::Coverage::Mode collectionMode);
Coverage() {}
};

View File

@ -281,8 +281,12 @@ class V8_EXPORT_PRIVATE Coverage {
uint32_t Count() const;
private:
explicit BlockData(i::CoverageBlock* block) : block_(block) {}
explicit BlockData(i::CoverageBlock* block,
std::shared_ptr<i::Coverage> coverage)
: block_(block), coverage_(std::move(coverage)) {}
i::CoverageBlock* block_;
std::shared_ptr<i::Coverage> coverage_;
friend class v8::debug::Coverage::FunctionData;
};
@ -300,9 +304,12 @@ class V8_EXPORT_PRIVATE Coverage {
BlockData GetBlockData(size_t i) const;
private:
explicit FunctionData(i::CoverageFunction* function)
: function_(function) {}
explicit FunctionData(i::CoverageFunction* function,
std::shared_ptr<i::Coverage> coverage)
: function_(function), coverage_(std::move(coverage)) {}
i::CoverageFunction* function_;
std::shared_ptr<i::Coverage> coverage_;
friend class v8::debug::Coverage::ScriptData;
};
@ -316,8 +323,10 @@ class V8_EXPORT_PRIVATE Coverage {
FunctionData GetFunctionData(size_t i) const;
private:
explicit ScriptData(i::CoverageScript* script) : script_(script) {}
explicit ScriptData(size_t index, std::shared_ptr<i::Coverage> c);
i::CoverageScript* script_;
std::shared_ptr<i::Coverage> coverage_;
friend class v8::debug::Coverage;
};
@ -331,11 +340,11 @@ class V8_EXPORT_PRIVATE Coverage {
ScriptData GetScriptData(size_t i) const;
bool IsEmpty() const { return coverage_ == nullptr; }
~Coverage();
~Coverage() = default;
private:
explicit Coverage(i::Coverage* coverage) : coverage_(coverage) {}
i::Coverage* coverage_;
explicit Coverage(std::shared_ptr<i::Coverage> coverage);
std::shared_ptr<i::Coverage> coverage_;
};
/*

View File

@ -1925,9 +1925,9 @@ RUNTIME_FUNCTION(Runtime_DebugCollectCoverage) {
// Collect coverage data.
std::unique_ptr<Coverage> coverage;
if (isolate->is_best_effort_code_coverage()) {
coverage.reset(Coverage::CollectBestEffort(isolate));
coverage = Coverage::CollectBestEffort(isolate);
} else {
coverage.reset(Coverage::CollectPrecise(isolate));
coverage = Coverage::CollectPrecise(isolate);
}
Factory* factory = isolate->factory();
// Turn the returned data structure into JavaScript.

View File

@ -6518,6 +6518,104 @@ TEST(DebugCoverage) {
CHECK_EQ(2, function_data.Count());
}
namespace {
v8::debug::Coverage::ScriptData GetScriptDataAndDeleteCoverage(
v8::Isolate* isolate) {
v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
CHECK_EQ(1u, coverage.ScriptCount());
return coverage.GetScriptData(0);
}
} // namespace
TEST(DebugCoverageWithCoverageOutOfScope) {
i::FLAG_always_opt = false;
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
v8::debug::Coverage::SelectMode(isolate, v8::debug::Coverage::kPreciseCount);
v8::Local<v8::String> source = v8_str(
"function f() {\n"
"}\n"
"f();\n"
"f();");
CompileRun(source);
v8::debug::Coverage::ScriptData script_data =
GetScriptDataAndDeleteCoverage(isolate);
v8::Local<v8::debug::Script> script = script_data.GetScript();
CHECK(script->Source()
.ToLocalChecked()
->Equals(env.local(), source)
.FromMaybe(false));
CHECK_EQ(2u, script_data.FunctionCount());
v8::debug::Coverage::FunctionData function_data =
script_data.GetFunctionData(0);
CHECK_EQ(0, function_data.StartOffset());
CHECK_EQ(26, function_data.EndOffset());
v8::debug::Location start =
script->GetSourceLocation(function_data.StartOffset());
v8::debug::Location end =
script->GetSourceLocation(function_data.EndOffset());
CHECK_EQ(0, start.GetLineNumber());
CHECK_EQ(0, start.GetColumnNumber());
CHECK_EQ(3, end.GetLineNumber());
CHECK_EQ(4, end.GetColumnNumber());
CHECK_EQ(1, function_data.Count());
function_data = script_data.GetFunctionData(1);
start = script->GetSourceLocation(function_data.StartOffset());
end = script->GetSourceLocation(function_data.EndOffset());
CHECK_EQ(0, function_data.StartOffset());
CHECK_EQ(16, function_data.EndOffset());
CHECK_EQ(0, start.GetLineNumber());
CHECK_EQ(0, start.GetColumnNumber());
CHECK_EQ(1, end.GetLineNumber());
CHECK_EQ(1, end.GetColumnNumber());
CHECK_EQ(2, function_data.Count());
}
namespace {
v8::debug::Coverage::FunctionData GetFunctionDataAndDeleteCoverage(
v8::Isolate* isolate) {
v8::debug::Coverage coverage = v8::debug::Coverage::CollectPrecise(isolate);
CHECK_EQ(1u, coverage.ScriptCount());
v8::debug::Coverage::ScriptData script_data = coverage.GetScriptData(0);
CHECK_EQ(2u, script_data.FunctionCount());
v8::debug::Coverage::FunctionData function_data =
script_data.GetFunctionData(0);
CHECK_EQ(1, function_data.Count());
CHECK_EQ(0, function_data.StartOffset());
CHECK_EQ(26, function_data.EndOffset());
return function_data;
}
} // namespace
TEST(DebugCoverageWithScriptDataOutOfScope) {
i::FLAG_always_opt = false;
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
v8::debug::Coverage::SelectMode(isolate, v8::debug::Coverage::kPreciseCount);
v8::Local<v8::String> source = v8_str(
"function f() {\n"
"}\n"
"f();\n"
"f();");
CompileRun(source);
v8::debug::Coverage::FunctionData function_data =
GetFunctionDataAndDeleteCoverage(isolate);
CHECK_EQ(1, function_data.Count());
CHECK_EQ(0, function_data.StartOffset());
CHECK_EQ(26, function_data.EndOffset());
}
TEST(BuiltinsExceptionPrediction) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope handle_scope(isolate);