[type-profile] Use vector list from isolate
Instead of re-iterating over the heap all the time, use the list of feedback vectors on the isolate. This also avoids GC of vectors. Bug: v8:5935 Change-Id: I0bb96fcf2b0feb9856e9806f812188de1fc7b37e Reviewed-on: https://chromium-review.googlesource.com/668396 Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Commit-Queue: Franziska Hinkelmann <franzih@chromium.org> Cr-Commit-Position: refs/heads/master@{#48643}
This commit is contained in:
parent
2aa434d2f5
commit
9b46f38392
@ -382,11 +382,12 @@ std::unique_ptr<Coverage> Coverage::CollectPrecise(Isolate* isolate) {
|
||||
DCHECK(!isolate->is_best_effort_code_coverage());
|
||||
std::unique_ptr<Coverage> result =
|
||||
Collect(isolate, isolate->code_coverage_mode());
|
||||
if (isolate->is_precise_binary_code_coverage() ||
|
||||
isolate->is_block_binary_code_coverage()) {
|
||||
if (!isolate->is_collecting_type_profile() &&
|
||||
(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
|
||||
// reported. So we can reset the list.
|
||||
isolate->SetCodeCoverageList(*ArrayList::New(isolate, 0));
|
||||
isolate->SetFeedbackVectorsForProfilingTools(*ArrayList::New(isolate, 0));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -407,9 +408,11 @@ std::unique_ptr<Coverage> Coverage::Collect(
|
||||
case v8::debug::Coverage::kPreciseBinary:
|
||||
case v8::debug::Coverage::kPreciseCount: {
|
||||
// Feedback vectors are already listed to prevent losing them to GC.
|
||||
DCHECK(isolate->factory()->code_coverage_list()->IsArrayList());
|
||||
Handle<ArrayList> list =
|
||||
Handle<ArrayList>::cast(isolate->factory()->code_coverage_list());
|
||||
DCHECK(isolate->factory()
|
||||
->feedback_vectors_for_profiling_tools()
|
||||
->IsArrayList());
|
||||
Handle<ArrayList> list = Handle<ArrayList>::cast(
|
||||
isolate->factory()->feedback_vectors_for_profiling_tools());
|
||||
for (int i = 0; i < list->Length(); i++) {
|
||||
FeedbackVector* vector = FeedbackVector::cast(list->Get(i));
|
||||
SharedFunctionInfo* shared = vector->shared_function_info();
|
||||
@ -421,7 +424,9 @@ std::unique_ptr<Coverage> Coverage::Collect(
|
||||
break;
|
||||
}
|
||||
case v8::debug::Coverage::kBestEffort: {
|
||||
DCHECK(!isolate->factory()->code_coverage_list()->IsArrayList());
|
||||
DCHECK(!isolate->factory()
|
||||
->feedback_vectors_for_profiling_tools()
|
||||
->IsArrayList());
|
||||
DCHECK_EQ(v8::debug::Coverage::kBestEffort, collectionMode);
|
||||
HeapIterator heap_iterator(isolate->heap());
|
||||
while (HeapObject* current_obj = heap_iterator.next()) {
|
||||
@ -520,7 +525,10 @@ void Coverage::SelectMode(Isolate* isolate, debug::Coverage::Mode mode) {
|
||||
// following coverage recording (without reloads) will be at function
|
||||
// granularity.
|
||||
isolate->debug()->RemoveAllCoverageInfos();
|
||||
isolate->SetCodeCoverageList(isolate->heap()->undefined_value());
|
||||
if (!isolate->is_collecting_type_profile()) {
|
||||
isolate->SetFeedbackVectorsForProfilingTools(
|
||||
isolate->heap()->undefined_value());
|
||||
}
|
||||
break;
|
||||
case debug::Coverage::kBlockBinary:
|
||||
case debug::Coverage::kBlockCount:
|
||||
@ -530,32 +538,11 @@ void Coverage::SelectMode(Isolate* isolate, debug::Coverage::Mode mode) {
|
||||
// Remove all optimized function. Optimized and inlined functions do not
|
||||
// increment invocation count.
|
||||
Deoptimizer::DeoptimizeAll(isolate);
|
||||
// Collect existing feedback vectors.
|
||||
std::vector<Handle<FeedbackVector>> vectors;
|
||||
{
|
||||
HeapIterator heap_iterator(isolate->heap());
|
||||
while (HeapObject* current_obj = heap_iterator.next()) {
|
||||
if (current_obj->IsSharedFunctionInfo()) {
|
||||
SharedFunctionInfo* shared = SharedFunctionInfo::cast(current_obj);
|
||||
shared->set_has_reported_binary_coverage(false);
|
||||
} else if (current_obj->IsFeedbackVector()) {
|
||||
FeedbackVector* vector = FeedbackVector::cast(current_obj);
|
||||
SharedFunctionInfo* shared = vector->shared_function_info();
|
||||
if (!shared->IsSubjectToDebugging()) continue;
|
||||
vector->clear_invocation_count();
|
||||
vectors.emplace_back(vector, isolate);
|
||||
} else if (current_obj->IsJSFunction()) {
|
||||
JSFunction* function = JSFunction::cast(current_obj);
|
||||
function->set_code(function->shared()->code());
|
||||
}
|
||||
}
|
||||
if (isolate->factory()
|
||||
->feedback_vectors_for_profiling_tools()
|
||||
->IsUndefined(isolate)) {
|
||||
isolate->InitializeVectorListFromHeap();
|
||||
}
|
||||
// Add collected feedback vectors to the root list lest we lose them to
|
||||
// GC.
|
||||
Handle<ArrayList> list =
|
||||
ArrayList::New(isolate, static_cast<int>(vectors.size()));
|
||||
for (const auto& vector : vectors) list = ArrayList::Add(list, vector);
|
||||
isolate->SetCodeCoverageList(*list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -15,19 +15,12 @@ namespace internal {
|
||||
std::unique_ptr<TypeProfile> TypeProfile::Collect(Isolate* isolate) {
|
||||
std::unique_ptr<TypeProfile> result(new TypeProfile());
|
||||
|
||||
// Collect existing feedback vectors.
|
||||
std::vector<Handle<FeedbackVector>> feedback_vectors;
|
||||
{
|
||||
HeapIterator heap_iterator(isolate->heap());
|
||||
while (HeapObject* current_obj = heap_iterator.next()) {
|
||||
if (current_obj->IsFeedbackVector()) {
|
||||
FeedbackVector* vector = FeedbackVector::cast(current_obj);
|
||||
SharedFunctionInfo* shared = vector->shared_function_info();
|
||||
if (!shared->IsSubjectToDebugging()) continue;
|
||||
feedback_vectors.emplace_back(vector, isolate);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Feedback vectors are already listed to prevent losing them to GC.
|
||||
DCHECK(isolate->factory()
|
||||
->feedback_vectors_for_profiling_tools()
|
||||
->IsArrayList());
|
||||
Handle<ArrayList> list = Handle<ArrayList>::cast(
|
||||
isolate->factory()->feedback_vectors_for_profiling_tools());
|
||||
|
||||
Script::Iterator scripts(isolate);
|
||||
|
||||
@ -41,7 +34,10 @@ std::unique_ptr<TypeProfile> TypeProfile::Collect(Isolate* isolate) {
|
||||
TypeProfileScript type_profile_script(script_handle);
|
||||
std::vector<TypeProfileEntry>* entries = &type_profile_script.entries;
|
||||
|
||||
for (const auto& vector : feedback_vectors) {
|
||||
// TODO(franzih): Sort the vectors by script first instead of iterating
|
||||
// the list multiple times.
|
||||
for (int i = 0; i < list->Length(); i++) {
|
||||
FeedbackVector* vector = FeedbackVector::cast(list->Get(i));
|
||||
SharedFunctionInfo* info = vector->shared_function_info();
|
||||
DCHECK(info->IsSubjectToDebugging());
|
||||
|
||||
@ -74,28 +70,47 @@ std::unique_ptr<TypeProfile> TypeProfile::Collect(Isolate* isolate) {
|
||||
}
|
||||
|
||||
void TypeProfile::SelectMode(Isolate* isolate, debug::TypeProfile::Mode mode) {
|
||||
isolate->set_type_profile_mode(mode);
|
||||
HandleScope handle_scope(isolate);
|
||||
|
||||
if (mode == debug::TypeProfile::Mode::kNone) {
|
||||
// Release type profile data collected so far.
|
||||
{
|
||||
HeapIterator heap_iterator(isolate->heap());
|
||||
while (HeapObject* current_obj = heap_iterator.next()) {
|
||||
if (current_obj->IsFeedbackVector()) {
|
||||
FeedbackVector* vector = FeedbackVector::cast(current_obj);
|
||||
SharedFunctionInfo* info = vector->shared_function_info();
|
||||
if (!info->IsSubjectToDebugging() ||
|
||||
info->feedback_metadata()->is_empty() ||
|
||||
!info->feedback_metadata()->HasTypeProfileSlot())
|
||||
continue;
|
||||
if (!isolate->factory()
|
||||
->feedback_vectors_for_profiling_tools()
|
||||
->IsUndefined(isolate)) {
|
||||
// Release type profile data collected so far.
|
||||
|
||||
// Feedback vectors are already listed to prevent losing them to GC.
|
||||
DCHECK(isolate->factory()
|
||||
->feedback_vectors_for_profiling_tools()
|
||||
->IsArrayList());
|
||||
Handle<ArrayList> list = Handle<ArrayList>::cast(
|
||||
isolate->factory()->feedback_vectors_for_profiling_tools());
|
||||
|
||||
for (int i = 0; i < list->Length(); i++) {
|
||||
FeedbackVector* vector = FeedbackVector::cast(list->Get(i));
|
||||
SharedFunctionInfo* info = vector->shared_function_info();
|
||||
DCHECK(info->IsSubjectToDebugging());
|
||||
if (info->feedback_metadata()->HasTypeProfileSlot()) {
|
||||
FeedbackSlot slot = vector->GetTypeProfileSlot();
|
||||
CollectTypeProfileNexus nexus(vector, slot);
|
||||
nexus.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the feedback vectors from the list if they're not used by code
|
||||
// coverage.
|
||||
if (isolate->is_best_effort_code_coverage()) {
|
||||
isolate->SetFeedbackVectorsForProfilingTools(
|
||||
isolate->heap()->undefined_value());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DCHECK_EQ(debug::TypeProfile::Mode::kCollect, mode);
|
||||
if (isolate->factory()->feedback_vectors_for_profiling_tools()->IsUndefined(
|
||||
isolate)) {
|
||||
isolate->InitializeVectorListFromHeap();
|
||||
}
|
||||
}
|
||||
isolate->set_type_profile_mode(mode);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -297,8 +297,9 @@ Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
|
||||
}
|
||||
|
||||
Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
|
||||
if (!isolate->is_best_effort_code_coverage()) {
|
||||
AddToCodeCoverageList(isolate, result);
|
||||
if (!isolate->is_best_effort_code_coverage() ||
|
||||
isolate->is_collecting_type_profile()) {
|
||||
AddToVectorsForProfilingTools(isolate, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -309,21 +310,23 @@ Handle<FeedbackVector> FeedbackVector::Copy(Isolate* isolate,
|
||||
Handle<FeedbackVector> result;
|
||||
result = Handle<FeedbackVector>::cast(
|
||||
isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
|
||||
if (!isolate->is_best_effort_code_coverage()) {
|
||||
AddToCodeCoverageList(isolate, result);
|
||||
if (!isolate->is_best_effort_code_coverage() ||
|
||||
isolate->is_collecting_type_profile()) {
|
||||
AddToVectorsForProfilingTools(isolate, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
void FeedbackVector::AddToCodeCoverageList(Isolate* isolate,
|
||||
Handle<FeedbackVector> vector) {
|
||||
DCHECK(!isolate->is_best_effort_code_coverage());
|
||||
void FeedbackVector::AddToVectorsForProfilingTools(
|
||||
Isolate* isolate, Handle<FeedbackVector> vector) {
|
||||
DCHECK(!isolate->is_best_effort_code_coverage() ||
|
||||
isolate->is_collecting_type_profile());
|
||||
if (!vector->shared_function_info()->IsSubjectToDebugging()) return;
|
||||
Handle<ArrayList> list =
|
||||
Handle<ArrayList>::cast(isolate->factory()->code_coverage_list());
|
||||
Handle<ArrayList> list = Handle<ArrayList>::cast(
|
||||
isolate->factory()->feedback_vectors_for_profiling_tools());
|
||||
list = ArrayList::Add(list, vector);
|
||||
isolate->SetCodeCoverageList(*list);
|
||||
isolate->SetFeedbackVectorsForProfilingTools(*list);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -278,8 +278,8 @@ class FeedbackVector : public HeapObject {
|
||||
}
|
||||
|
||||
private:
|
||||
static void AddToCodeCoverageList(Isolate* isolate,
|
||||
Handle<FeedbackVector> vector);
|
||||
static void AddToVectorsForProfilingTools(Isolate* isolate,
|
||||
Handle<FeedbackVector> vector);
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(FeedbackVector);
|
||||
};
|
||||
|
@ -2559,7 +2559,7 @@ bool Heap::RootCanBeWrittenAfterInitialization(Heap::RootListIndex root_index) {
|
||||
case kWeakNewSpaceObjectToCodeListRootIndex:
|
||||
case kRetainedMapsRootIndex:
|
||||
case kRetainingPathTargetsRootIndex:
|
||||
case kCodeCoverageListRootIndex:
|
||||
case kFeedbackVectorsForProfilingToolsRootIndex:
|
||||
case kNoScriptSharedFunctionInfosRootIndex:
|
||||
case kWeakStackTraceListRootIndex:
|
||||
case kSerializedTemplatesRootIndex:
|
||||
|
@ -227,8 +227,9 @@ using v8::MemoryPressureLevel;
|
||||
/* slots refer to the code with the reference to the weak object. */ \
|
||||
V(ArrayList, weak_new_space_object_to_code_list, \
|
||||
WeakNewSpaceObjectToCodeList) \
|
||||
/* List to hold onto feedback vectors that we need for code coverage */ \
|
||||
V(Object, code_coverage_list, CodeCoverageList) \
|
||||
/* Feedback vectors that we need for code coverage or type profile */ \
|
||||
V(Object, feedback_vectors_for_profiling_tools, \
|
||||
FeedbackVectorsForProfilingTools) \
|
||||
V(Object, weak_stack_trace_list, WeakStackTraceList) \
|
||||
V(Object, noscript_shared_function_infos, NoScriptSharedFunctionInfos) \
|
||||
V(FixedArray, serialized_templates, SerializedTemplates) \
|
||||
|
@ -542,7 +542,7 @@ void Heap::CreateInitialObjects() {
|
||||
ArrayList::cast(*(factory->NewFixedArray(16, TENURED))));
|
||||
weak_new_space_object_to_code_list()->SetLength(0);
|
||||
|
||||
set_code_coverage_list(undefined_value());
|
||||
set_feedback_vectors_for_profiling_tools(undefined_value());
|
||||
|
||||
set_script_list(Smi::kZero);
|
||||
|
||||
|
@ -3030,9 +3030,39 @@ bool Isolate::NeedsSourcePositionsForProfiling() const {
|
||||
debug_->is_active() || logger_->is_logging();
|
||||
}
|
||||
|
||||
void Isolate::SetCodeCoverageList(Object* value) {
|
||||
void Isolate::SetFeedbackVectorsForProfilingTools(Object* value) {
|
||||
DCHECK(value->IsUndefined(this) || value->IsArrayList());
|
||||
heap()->set_code_coverage_list(value);
|
||||
heap()->set_feedback_vectors_for_profiling_tools(value);
|
||||
}
|
||||
|
||||
void Isolate::InitializeVectorListFromHeap() {
|
||||
// Collect existing feedback vectors.
|
||||
std::vector<Handle<FeedbackVector>> vectors;
|
||||
{
|
||||
HeapIterator heap_iterator(heap());
|
||||
while (HeapObject* current_obj = heap_iterator.next()) {
|
||||
if (current_obj->IsSharedFunctionInfo()) {
|
||||
SharedFunctionInfo* shared = SharedFunctionInfo::cast(current_obj);
|
||||
shared->set_has_reported_binary_coverage(false);
|
||||
} else if (current_obj->IsFeedbackVector()) {
|
||||
FeedbackVector* vector = FeedbackVector::cast(current_obj);
|
||||
SharedFunctionInfo* shared = vector->shared_function_info();
|
||||
if (!shared->IsSubjectToDebugging()) continue;
|
||||
vector->clear_invocation_count();
|
||||
vectors.emplace_back(vector, this);
|
||||
} else if (current_obj->IsJSFunction()) {
|
||||
JSFunction* function = JSFunction::cast(current_obj);
|
||||
function->set_code(function->shared()->code());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add collected feedback vectors to the root list lest we lose them to
|
||||
// GC.
|
||||
Handle<ArrayList> list =
|
||||
ArrayList::New(this, static_cast<int>(vectors.size()));
|
||||
for (const auto& vector : vectors) list = ArrayList::Add(list, vector);
|
||||
SetFeedbackVectorsForProfilingTools(*list);
|
||||
}
|
||||
|
||||
bool Isolate::IsArrayOrObjectPrototype(Object* object) {
|
||||
|
@ -1056,7 +1056,14 @@ class Isolate {
|
||||
return type_profile_mode() == debug::TypeProfile::kCollect;
|
||||
}
|
||||
|
||||
void SetCodeCoverageList(Object* value);
|
||||
// Collect feedback vectors with data for code coverage or type profile.
|
||||
// Reset the list, when both code coverage and type profile are not
|
||||
// needed anymore. This keeps many feedback vectors alive, but code
|
||||
// coverage or type profile are used for debugging only and increase in
|
||||
// memory usage is expected.
|
||||
void SetFeedbackVectorsForProfilingTools(Object* value);
|
||||
|
||||
void InitializeVectorListFromHeap();
|
||||
|
||||
double time_millis_since_init() {
|
||||
return heap_.MonotonicallyIncreasingTimeInMs() - time_millis_at_init_;
|
||||
|
@ -47,3 +47,5 @@ function f(/*null*/a) {
|
||||
return 'second';
|
||||
/*string*/};
|
||||
f(null);
|
||||
|
||||
Running test: testStopTwice
|
||||
|
@ -166,5 +166,13 @@ InspectorTest.runAsyncTestSuite([
|
||||
Protocol.Profiler.stopTypeProfile();
|
||||
Protocol.Profiler.disable();
|
||||
await Protocol.Runtime.disable();
|
||||
}
|
||||
},
|
||||
async function testStopTwice() {
|
||||
Protocol.Runtime.enable();
|
||||
await Protocol.Profiler.enable();
|
||||
await Protocol.Profiler.stopTypeProfile();
|
||||
await Protocol.Profiler.stopTypeProfile();
|
||||
Protocol.Profiler.disable();
|
||||
await Protocol.Runtime.disable();
|
||||
},
|
||||
]);
|
||||
|
Loading…
Reference in New Issue
Block a user