Revert "[cpu-profiler] Implement weak phantom finalizers for CodeMap entries"
This reverts commit 3a405b01ba
.
Reason for revert: thread-sanitizer failures on Linux64 TSAN bot:
https://ci.chromium.org/ui/p/v8/builders/ci/V8%20Linux64%20TSAN/35141/overview
Original change's description:
> [cpu-profiler] Implement weak phantom finalizers for CodeMap entries
>
> Listen to code deletion events by registering finalizers on code
> objects, a first stab at non-leaky long-lived code entries.
>
> Bug: v8:11054
> Change-Id: Ieaaa5b63508263bd261e8385f5bf5dd3baedf9c5
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2628587
> Commit-Queue: Andrew Comminos <acomminos@fb.com>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Peter Marshall <petermarshall@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#72342}
TBR=ulan@chromium.org,petermarshall@chromium.org,acomminos@fb.com
Change-Id: If22a893af469c9d4d3e00fb124c42cdc52b9a19b
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:11054
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2649156
Reviewed-by: Adam Klein <adamk@chromium.org>
Commit-Queue: Adam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72344}
This commit is contained in:
parent
29b4d2a1b4
commit
cb1a2c98e7
@ -42,9 +42,6 @@ void CodeDeoptEventRecord::UpdateCodeMap(CodeMap* code_map) {
|
|||||||
delete[] deopt_frames;
|
delete[] deopt_frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeSweepEventRecord::UpdateCodeMap(CodeMap* code_map) {
|
|
||||||
code_map->ClearUnused();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReportBuiltinEventRecord::UpdateCodeMap(CodeMap* code_map) {
|
void ReportBuiltinEventRecord::UpdateCodeMap(CodeMap* code_map) {
|
||||||
CodeEntry* entry = code_map->FindEntry(instruction_start);
|
CodeEntry* entry = code_map->FindEntry(instruction_start);
|
||||||
|
@ -85,15 +85,6 @@ ProfilingScope::ProfilingScope(Isolate* isolate, ProfilerListener* listener)
|
|||||||
}
|
}
|
||||||
logger->LogCompiledFunctions();
|
logger->LogCompiledFunctions();
|
||||||
logger->LogAccessorCallbacks();
|
logger->LogAccessorCallbacks();
|
||||||
|
|
||||||
// Trigger dead code to be cleared from the CodeMap on GC.
|
|
||||||
isolate_->heap()->AddGCEpilogueCallback(SweepCallback,
|
|
||||||
kGCTypeMarkSweepCompact, listener_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProfilingScope::SweepCallback(v8::Isolate*, v8::GCType,
|
|
||||||
v8::GCCallbackFlags, void* listener) {
|
|
||||||
reinterpret_cast<ProfilerListener*>(listener)->CodeSweepEvent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfilingScope::~ProfilingScope() {
|
ProfilingScope::~ProfilingScope() {
|
||||||
@ -104,7 +95,6 @@ ProfilingScope::~ProfilingScope() {
|
|||||||
profiler_count--;
|
profiler_count--;
|
||||||
isolate_->set_num_cpu_profilers(profiler_count);
|
isolate_->set_num_cpu_profilers(profiler_count);
|
||||||
if (profiler_count == 0) isolate_->set_is_profiling(false);
|
if (profiler_count == 0) isolate_->set_is_profiling(false);
|
||||||
isolate_->heap()->RemoveGCEpilogueCallback(SweepCallback, listener_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfilerEventsProcessor::ProfilerEventsProcessor(
|
ProfilerEventsProcessor::ProfilerEventsProcessor(
|
||||||
@ -206,7 +196,6 @@ void ProfilerEventsProcessor::CodeEventHandler(
|
|||||||
case CodeEventRecord::CODE_CREATION:
|
case CodeEventRecord::CODE_CREATION:
|
||||||
case CodeEventRecord::CODE_MOVE:
|
case CodeEventRecord::CODE_MOVE:
|
||||||
case CodeEventRecord::CODE_DISABLE_OPT:
|
case CodeEventRecord::CODE_DISABLE_OPT:
|
||||||
case CodeEventRecord::CODE_SWEEP:
|
|
||||||
Enqueue(evt_rec);
|
Enqueue(evt_rec);
|
||||||
break;
|
break;
|
||||||
case CodeEventRecord::CODE_DEOPT: {
|
case CodeEventRecord::CODE_DEOPT: {
|
||||||
|
@ -34,7 +34,6 @@ class Symbolizer;
|
|||||||
V(CODE_MOVE, CodeMoveEventRecord) \
|
V(CODE_MOVE, CodeMoveEventRecord) \
|
||||||
V(CODE_DISABLE_OPT, CodeDisableOptEventRecord) \
|
V(CODE_DISABLE_OPT, CodeDisableOptEventRecord) \
|
||||||
V(CODE_DEOPT, CodeDeoptEventRecord) \
|
V(CODE_DEOPT, CodeDeoptEventRecord) \
|
||||||
V(CODE_SWEEP, CodeSweepEventRecord) \
|
|
||||||
V(REPORT_BUILTIN, ReportBuiltinEventRecord)
|
V(REPORT_BUILTIN, ReportBuiltinEventRecord)
|
||||||
|
|
||||||
class CodeEventRecord {
|
class CodeEventRecord {
|
||||||
@ -89,10 +88,6 @@ class CodeDeoptEventRecord : public CodeEventRecord {
|
|||||||
V8_INLINE void UpdateCodeMap(CodeMap* code_map);
|
V8_INLINE void UpdateCodeMap(CodeMap* code_map);
|
||||||
};
|
};
|
||||||
|
|
||||||
class CodeSweepEventRecord : public CodeEventRecord {
|
|
||||||
public:
|
|
||||||
V8_INLINE void UpdateCodeMap(CodeMap* code_map);
|
|
||||||
};
|
|
||||||
|
|
||||||
class ReportBuiltinEventRecord : public CodeEventRecord {
|
class ReportBuiltinEventRecord : public CodeEventRecord {
|
||||||
public:
|
public:
|
||||||
@ -140,9 +135,6 @@ class V8_NODISCARD ProfilingScope {
|
|||||||
~ProfilingScope();
|
~ProfilingScope();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void SweepCallback(v8::Isolate*, v8::GCType, v8::GCCallbackFlags,
|
|
||||||
void* listener);
|
|
||||||
|
|
||||||
Isolate* const isolate_;
|
Isolate* const isolate_;
|
||||||
ProfilerListener* const listener_;
|
ProfilerListener* const listener_;
|
||||||
};
|
};
|
||||||
|
@ -719,29 +719,9 @@ CodeMap::CodeMap(StringsStorage& function_and_resource_names)
|
|||||||
|
|
||||||
CodeMap::~CodeMap() { Clear(); }
|
CodeMap::~CodeMap() { Clear(); }
|
||||||
|
|
||||||
size_t CodeMap::ClearUnused() {
|
|
||||||
size_t num_freed = 0;
|
|
||||||
for (auto it = code_map_.begin(); it != code_map_.end();) {
|
|
||||||
auto* entry = it->second.entry;
|
|
||||||
DCHECK(entry);
|
|
||||||
|
|
||||||
// If a CodeEntry is not used by a profile and its heap object
|
|
||||||
// representation has been deallocated, remove the entry.
|
|
||||||
if (!entry->used() && entry->IsHeapObjectFreed()) {
|
|
||||||
DeleteCodeEntry(entry);
|
|
||||||
it = code_map_.erase(it);
|
|
||||||
num_freed++;
|
|
||||||
} else {
|
|
||||||
it++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return num_freed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeMap::Clear() {
|
void CodeMap::Clear() {
|
||||||
for (auto& slot : code_map_) {
|
for (auto& slot : code_map_) {
|
||||||
if (CodeEntry* entry = slot.second.entry) {
|
if (CodeEntry* entry = slot.second.entry) {
|
||||||
entry->UntrackHeapObject();
|
|
||||||
entry->ReleaseStrings(function_and_resource_names_);
|
entry->ReleaseStrings(function_and_resource_names_);
|
||||||
delete entry;
|
delete entry;
|
||||||
} else {
|
} else {
|
||||||
|
@ -17,8 +17,6 @@
|
|||||||
#include "include/v8-profiler.h"
|
#include "include/v8-profiler.h"
|
||||||
#include "src/base/platform/time.h"
|
#include "src/base/platform/time.h"
|
||||||
#include "src/builtins/builtins.h"
|
#include "src/builtins/builtins.h"
|
||||||
#include "src/execution/isolate.h"
|
|
||||||
#include "src/handles/global-handles.h"
|
|
||||||
#include "src/logging/code-events.h"
|
#include "src/logging/code-events.h"
|
||||||
#include "src/profiler/strings-storage.h"
|
#include "src/profiler/strings-storage.h"
|
||||||
#include "src/utils/allocation.h"
|
#include "src/utils/allocation.h"
|
||||||
@ -104,8 +102,8 @@ class CodeEntry {
|
|||||||
rare_data_->deopt_reason_ = kNoDeoptReason;
|
rare_data_->deopt_reason_ = kNoDeoptReason;
|
||||||
rare_data_->deopt_id_ = kNoDeoptimizationId;
|
rare_data_->deopt_id_ = kNoDeoptimizationId;
|
||||||
}
|
}
|
||||||
void mark_used() { used_ = true; }
|
void mark_used() { bit_field_ = UsedField::update(bit_field_, true); }
|
||||||
bool used() const { return used_; }
|
bool used() const { return UsedField::decode(bit_field_); }
|
||||||
|
|
||||||
const char* code_type_string() const {
|
const char* code_type_string() const {
|
||||||
switch (CodeTypeField::decode(bit_field_)) {
|
switch (CodeTypeField::decode(bit_field_)) {
|
||||||
@ -118,38 +116,8 @@ class CodeEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_tracking_heap_object() const {
|
|
||||||
return TrackingHeapObjectField::decode(bit_field_);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsHeapObjectFreed() const {
|
|
||||||
return is_tracking_heap_object() && heap_object_handle_location_ == nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FillFunctionInfo(SharedFunctionInfo shared);
|
void FillFunctionInfo(SharedFunctionInfo shared);
|
||||||
|
|
||||||
// Associates this CodeEntry with the given heap object, taking a weak
|
|
||||||
// reference to it. Must be called on the isolate thread.
|
|
||||||
template <typename T>
|
|
||||||
void TrackHeapObject(Isolate* isolate, Handle<T> object) {
|
|
||||||
DCHECK(!is_tracking_heap_object());
|
|
||||||
bit_field_ = TrackingHeapObjectField::update(bit_field_, true);
|
|
||||||
heap_object_handle_location_ =
|
|
||||||
isolate->global_handles()->Create(*object).location();
|
|
||||||
GlobalHandles::MakeWeak(&heap_object_handle_location_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clears out any weak reference set by TrackHeapObject. Must be called on
|
|
||||||
// the isolate thread.
|
|
||||||
void UntrackHeapObject() {
|
|
||||||
if (is_tracking_heap_object()) {
|
|
||||||
bit_field_ = TrackingHeapObjectField::update(bit_field_, false);
|
|
||||||
if (heap_object_handle_location_) {
|
|
||||||
GlobalHandles::ClearWeakness(heap_object_handle_location_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetBuiltinId(Builtins::Name id);
|
void SetBuiltinId(Builtins::Name id);
|
||||||
Builtins::Name builtin_id() const {
|
Builtins::Name builtin_id() const {
|
||||||
return BuiltinIdField::decode(bit_field_);
|
return BuiltinIdField::decode(bit_field_);
|
||||||
@ -232,23 +200,20 @@ class CodeEntry {
|
|||||||
static_assert(Builtins::builtin_count <= BuiltinIdField::kNumValues,
|
static_assert(Builtins::builtin_count <= BuiltinIdField::kNumValues,
|
||||||
"builtin_count exceeds size of bitfield");
|
"builtin_count exceeds size of bitfield");
|
||||||
using CodeTypeField = base::BitField<CodeType, 28, 2>;
|
using CodeTypeField = base::BitField<CodeType, 28, 2>;
|
||||||
using TrackingHeapObjectField = base::BitField<bool, 30, 1>;
|
using UsedField = base::BitField<bool, 30, 1>;
|
||||||
using SharedCrossOriginField = base::BitField<bool, 31, 1>;
|
using SharedCrossOriginField = base::BitField<bool, 31, 1>;
|
||||||
|
|
||||||
std::uint32_t bit_field_;
|
// Atomic because Used is written from the profiler thread while CodeType is
|
||||||
|
// read from the main thread.
|
||||||
|
std::atomic<std::uint32_t> bit_field_;
|
||||||
const char* name_;
|
const char* name_;
|
||||||
const char* resource_name_;
|
const char* resource_name_;
|
||||||
int line_number_;
|
int line_number_;
|
||||||
int column_number_;
|
int column_number_;
|
||||||
int script_id_;
|
int script_id_;
|
||||||
int position_;
|
int position_;
|
||||||
// We use a full byte here instead of a bitfield to avoid raciness between
|
|
||||||
// the main thread and profiler thread.
|
|
||||||
// TODO(acomminos): Remove this after atomic reference counting is added.
|
|
||||||
std::uint8_t used_ = false;
|
|
||||||
std::unique_ptr<SourcePositionTable> line_info_;
|
std::unique_ptr<SourcePositionTable> line_info_;
|
||||||
std::unique_ptr<RareData> rare_data_;
|
std::unique_ptr<RareData> rare_data_;
|
||||||
Address* heap_object_handle_location_ = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CodeEntryAndLineNumber {
|
struct CodeEntryAndLineNumber {
|
||||||
@ -444,12 +409,6 @@ class V8_EXPORT_PRIVATE CodeMap {
|
|||||||
CodeEntry* FindEntry(Address addr, Address* out_instruction_start = nullptr);
|
CodeEntry* FindEntry(Address addr, Address* out_instruction_start = nullptr);
|
||||||
void Print();
|
void Print();
|
||||||
|
|
||||||
// Frees all CodeMap entries that no longer have a heap object, and are not
|
|
||||||
// being included in any profiles.
|
|
||||||
size_t ClearUnused();
|
|
||||||
|
|
||||||
size_t size() const { return code_map_.size(); }
|
|
||||||
|
|
||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -43,7 +43,6 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
|
|||||||
rec->entry = new CodeEntry(tag, GetName(name), CodeEntry::kEmptyResourceName,
|
rec->entry = new CodeEntry(tag, GetName(name), CodeEntry::kEmptyResourceName,
|
||||||
CpuProfileNode::kNoLineNumberInfo,
|
CpuProfileNode::kNoLineNumberInfo,
|
||||||
CpuProfileNode::kNoColumnNumberInfo, nullptr);
|
CpuProfileNode::kNoColumnNumberInfo, nullptr);
|
||||||
rec->entry->TrackHeapObject(isolate_, code);
|
|
||||||
rec->instruction_size = code->InstructionSize();
|
rec->instruction_size = code->InstructionSize();
|
||||||
DispatchCodeEvent(evt_rec);
|
DispatchCodeEvent(evt_rec);
|
||||||
}
|
}
|
||||||
@ -57,7 +56,6 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
|
|||||||
rec->entry = new CodeEntry(tag, GetName(*name), CodeEntry::kEmptyResourceName,
|
rec->entry = new CodeEntry(tag, GetName(*name), CodeEntry::kEmptyResourceName,
|
||||||
CpuProfileNode::kNoLineNumberInfo,
|
CpuProfileNode::kNoLineNumberInfo,
|
||||||
CpuProfileNode::kNoColumnNumberInfo, nullptr);
|
CpuProfileNode::kNoColumnNumberInfo, nullptr);
|
||||||
rec->entry->TrackHeapObject(isolate_, code);
|
|
||||||
rec->instruction_size = code->InstructionSize();
|
rec->instruction_size = code->InstructionSize();
|
||||||
DispatchCodeEvent(evt_rec);
|
DispatchCodeEvent(evt_rec);
|
||||||
}
|
}
|
||||||
@ -75,7 +73,6 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
|
|||||||
CpuProfileNode::kNoColumnNumberInfo, nullptr);
|
CpuProfileNode::kNoColumnNumberInfo, nullptr);
|
||||||
DCHECK(!code->IsCode());
|
DCHECK(!code->IsCode());
|
||||||
rec->entry->FillFunctionInfo(*shared);
|
rec->entry->FillFunctionInfo(*shared);
|
||||||
rec->entry->TrackHeapObject(isolate_, code);
|
|
||||||
rec->instruction_size = code->InstructionSize();
|
rec->instruction_size = code->InstructionSize();
|
||||||
DispatchCodeEvent(evt_rec);
|
DispatchCodeEvent(evt_rec);
|
||||||
}
|
}
|
||||||
@ -198,7 +195,6 @@ void ProfilerListener::CodeCreateEvent(LogEventsAndTags tag,
|
|||||||
}
|
}
|
||||||
|
|
||||||
rec->entry->FillFunctionInfo(*shared);
|
rec->entry->FillFunctionInfo(*shared);
|
||||||
rec->entry->TrackHeapObject(isolate_, abstract_code);
|
|
||||||
rec->instruction_size = abstract_code->InstructionSize();
|
rec->instruction_size = abstract_code->InstructionSize();
|
||||||
DispatchCodeEvent(evt_rec);
|
DispatchCodeEvent(evt_rec);
|
||||||
}
|
}
|
||||||
@ -303,11 +299,6 @@ void ProfilerListener::CodeDeoptEvent(Handle<Code> code, DeoptimizeKind kind,
|
|||||||
DispatchCodeEvent(evt_rec);
|
DispatchCodeEvent(evt_rec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProfilerListener::CodeSweepEvent() {
|
|
||||||
CodeEventsContainer evt_rec(CodeEventRecord::CODE_SWEEP);
|
|
||||||
DispatchCodeEvent(evt_rec);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* ProfilerListener::GetName(Vector<const char> name) {
|
const char* ProfilerListener::GetName(Vector<const char> name) {
|
||||||
// TODO(all): Change {StringsStorage} to accept non-null-terminated strings.
|
// TODO(all): Change {StringsStorage} to accept non-null-terminated strings.
|
||||||
OwnedVector<char> null_terminated = OwnedVector<char>::New(name.size() + 1);
|
OwnedVector<char> null_terminated = OwnedVector<char>::New(name.size() + 1);
|
||||||
|
@ -62,7 +62,6 @@ class V8_EXPORT_PRIVATE ProfilerListener : public CodeEventListener {
|
|||||||
void CodeDependencyChangeEvent(Handle<Code> code,
|
void CodeDependencyChangeEvent(Handle<Code> code,
|
||||||
Handle<SharedFunctionInfo> sfi,
|
Handle<SharedFunctionInfo> sfi,
|
||||||
const char* reason) override {}
|
const char* reason) override {}
|
||||||
void CodeSweepEvent();
|
|
||||||
|
|
||||||
const char* GetName(Name name) {
|
const char* GetName(Name name) {
|
||||||
return function_and_resource_names_.GetName(name);
|
return function_and_resource_names_.GetName(name);
|
||||||
|
@ -4075,38 +4075,6 @@ TEST(FastApiCPUProfiler) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that unused code entries are removed after GC with eager logging.
|
|
||||||
TEST(ClearUnusedWithEagerLogging) {
|
|
||||||
ManualGCScope manual_gc;
|
|
||||||
TestSetup test_setup;
|
|
||||||
LocalContext env;
|
|
||||||
i::Isolate* isolate = CcTest::i_isolate();
|
|
||||||
i::HandleScope scope(isolate);
|
|
||||||
|
|
||||||
CpuProfiler profiler(isolate, kDebugNaming, kEagerLogging);
|
|
||||||
|
|
||||||
CodeMap* code_map = profiler.code_map_for_test();
|
|
||||||
size_t initial_size = code_map->size();
|
|
||||||
|
|
||||||
{
|
|
||||||
// Create and run a new script and function, generating 2 code objects.
|
|
||||||
i::HandleScope inner_scope(isolate);
|
|
||||||
CompileRun(
|
|
||||||
"function some_func() {}"
|
|
||||||
"some_func();");
|
|
||||||
CHECK_GT(code_map->size(), initial_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform a few GCs, ensuring that the executed code's bytecode is flushed.
|
|
||||||
const int kAgingThreshold = 8;
|
|
||||||
for (int i = 0; i < kAgingThreshold; i++) {
|
|
||||||
CcTest::CollectAllGarbage();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that the CodeMap's size is unchanged post-GC.
|
|
||||||
CHECK_EQ(code_map->size(), initial_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace test_cpu_profiler
|
} // namespace test_cpu_profiler
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -851,50 +851,6 @@ TEST(NodeSourceTypes) {
|
|||||||
CHECK_EQ(unresolved_node->source_type(), v8::CpuProfileNode::kUnresolved);
|
CHECK_EQ(unresolved_node->source_type(), v8::CpuProfileNode::kUnresolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(CodeMapClearUnused) {
|
|
||||||
Isolate* isolate = CcTest::i_isolate();
|
|
||||||
|
|
||||||
StringsStorage strings;
|
|
||||||
CodeMap code_map(strings);
|
|
||||||
|
|
||||||
auto* entry = new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "aaa");
|
|
||||||
code_map.AddCode(0, entry, 1);
|
|
||||||
|
|
||||||
// Ensure that CodeEntry objects without a heap object aren't cleared.
|
|
||||||
CHECK_EQ(code_map.ClearUnused(), 0);
|
|
||||||
|
|
||||||
auto* gc_entry_unused =
|
|
||||||
new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "bbb");
|
|
||||||
code_map.AddCode(0x10, gc_entry_unused, 1);
|
|
||||||
|
|
||||||
auto* gc_entry_used =
|
|
||||||
new CodeEntry(i::CodeEventListener::FUNCTION_TAG, "ccc");
|
|
||||||
gc_entry_used->mark_used();
|
|
||||||
code_map.AddCode(0x20, gc_entry_used, 1);
|
|
||||||
|
|
||||||
{
|
|
||||||
HandleScope scope(isolate);
|
|
||||||
|
|
||||||
// Temporarily associate a random heap object with the entries.
|
|
||||||
Handle<FixedArray> stub_object = isolate->factory()->NewFixedArray(1);
|
|
||||||
gc_entry_used->TrackHeapObject(isolate, stub_object);
|
|
||||||
gc_entry_unused->TrackHeapObject(isolate, stub_object);
|
|
||||||
|
|
||||||
// Ensure that the entries aren't dropped while the object is alive.
|
|
||||||
CcTest::CollectAllGarbage();
|
|
||||||
CHECK_EQ(code_map.ClearUnused(), 0);
|
|
||||||
CHECK_EQ(code_map.FindEntry(0x10), gc_entry_unused);
|
|
||||||
CHECK_EQ(code_map.FindEntry(0x20), gc_entry_used);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that the unused CodeEntry associated with a gc'd address is dropped
|
|
||||||
// after the handle is lost, but the used one isn't.
|
|
||||||
CcTest::CollectAllGarbage();
|
|
||||||
CHECK_EQ(code_map.ClearUnused(), 1);
|
|
||||||
CHECK_EQ(code_map.FindEntry(0x10), nullptr);
|
|
||||||
CHECK_EQ(code_map.FindEntry(0x20), gc_entry_used);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace test_profile_generator
|
} // namespace test_profile_generator
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
Loading…
Reference in New Issue
Block a user