Commit a702d2fe authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

heap: Fixes for copying/moving traced references

- Fix copying of already initialized nodes
- Add better verification
- Add tests for moving/copying onto already initialized nodes

Bug: chromium:1040038
Change-Id: I0c144fcfe980d7542cf6803e4dc861e3fd4ca708
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2007278Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65858}
parent 2b552e92
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/handles/global-handles.h" #include "src/handles/global-handles.h"
#include <algorithm>
#include <map> #include <map>
#include "src/api/api-inl.h" #include "src/api/api-inl.h"
...@@ -626,7 +627,6 @@ class GlobalHandles::TracedNode final ...@@ -626,7 +627,6 @@ class GlobalHandles::TracedNode final
// instead of move ctor.) // instead of move ctor.)
TracedNode(TracedNode&& other) V8_NOEXCEPT = default; TracedNode(TracedNode&& other) V8_NOEXCEPT = default;
TracedNode(const TracedNode& other) V8_NOEXCEPT = default; TracedNode(const TracedNode& other) V8_NOEXCEPT = default;
TracedNode& operator=(const TracedNode& other) V8_NOEXCEPT = default;
enum State { FREE = 0, NORMAL, NEAR_DEATH }; enum State { FREE = 0, NORMAL, NEAR_DEATH };
...@@ -662,6 +662,8 @@ class GlobalHandles::TracedNode final ...@@ -662,6 +662,8 @@ class GlobalHandles::TracedNode final
} }
bool HasFinalizationCallback() const { return callback_ != nullptr; } bool HasFinalizationCallback() const { return callback_ != nullptr; }
void CopyObjectReference(const TracedNode& other) { object_ = other.object_; }
void CollectPhantomCallbackData( void CollectPhantomCallbackData(
std::vector<std::pair<TracedNode*, PendingPhantomCallback>>* std::vector<std::pair<TracedNode*, PendingPhantomCallback>>*
pending_phantom_callbacks) { pending_phantom_callbacks) {
...@@ -691,11 +693,7 @@ class GlobalHandles::TracedNode final ...@@ -691,11 +693,7 @@ class GlobalHandles::TracedNode final
DCHECK(!IsInUse()); DCHECK(!IsInUse());
} }
void Verify() { static void Verify(GlobalHandles* global_handles, const Address* const* slot);
DCHECK(IsInUse());
DCHECK_IMPLIES(!has_destructor(), nullptr == parameter());
DCHECK_IMPLIES(has_destructor() && !HasFinalizationCallback(), parameter());
}
protected: protected:
using NodeState = base::BitField8<State, 0, 2>; using NodeState = base::BitField8<State, 0, 2>;
...@@ -844,6 +842,31 @@ void GlobalHandles::OnStackTracedNodeSpace::CleanupBelowCurrentStackPosition() { ...@@ -844,6 +842,31 @@ void GlobalHandles::OnStackTracedNodeSpace::CleanupBelowCurrentStackPosition() {
on_stack_nodes_.erase(on_stack_nodes_.begin(), it); on_stack_nodes_.erase(on_stack_nodes_.begin(), it);
} }
// static
void GlobalHandles::TracedNode::Verify(GlobalHandles* global_handles,
const Address* const* slot) {
#ifdef DEBUG
const TracedNode* node = FromLocation(*slot);
DCHECK(node->IsInUse());
DCHECK_IMPLIES(!node->has_destructor(), nullptr == node->parameter());
DCHECK_IMPLIES(node->has_destructor() && !node->HasFinalizationCallback(),
node->parameter());
bool slot_on_stack = global_handles->on_stack_nodes_->IsOnStack(
reinterpret_cast<uintptr_t>(slot));
DCHECK_EQ(slot_on_stack, node->is_on_stack());
if (!node->is_on_stack()) {
// On-heap nodes have seprate lists for young generation processing.
bool is_young_gen_object = ObjectInYoungGeneration(node->object());
DCHECK_IMPLIES(is_young_gen_object, node->is_in_young_list());
}
bool in_young_list =
std::find(global_handles->traced_young_nodes_.begin(),
global_handles->traced_young_nodes_.end(),
node) != global_handles->traced_young_nodes_.end();
DCHECK_EQ(in_young_list, node->is_in_young_list());
#endif // DEBUG
}
void GlobalHandles::CleanupOnStackReferencesBelowCurrentStackPosition() { void GlobalHandles::CleanupOnStackReferencesBelowCurrentStackPosition() {
on_stack_nodes_->CleanupBelowCurrentStackPosition(); on_stack_nodes_->CleanupBelowCurrentStackPosition();
} }
...@@ -940,6 +963,8 @@ void GlobalHandles::CopyTracedGlobal(const Address* const* from, Address** to) { ...@@ -940,6 +963,8 @@ void GlobalHandles::CopyTracedGlobal(const Address* const* from, Address** to) {
Handle<Object> o = global_handles->CreateTraced( Handle<Object> o = global_handles->CreateTraced(
node->object(), reinterpret_cast<Address*>(to), node->has_destructor()); node->object(), reinterpret_cast<Address*>(to), node->has_destructor());
*to = o.location(); *to = o.location();
TracedNode::Verify(global_handles, from);
TracedNode::Verify(global_handles, to);
#ifdef VERIFY_HEAP #ifdef VERIFY_HEAP
if (i::FLAG_verify_heap) { if (i::FLAG_verify_heap) {
Object(**to).ObjectVerify(global_handles->isolate()); Object(**to).ObjectVerify(global_handles->isolate());
...@@ -971,8 +996,12 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) { ...@@ -971,8 +996,12 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) {
// Determining whether from or to are on stack. // Determining whether from or to are on stack.
TracedNode* from_node = TracedNode::FromLocation(*from); TracedNode* from_node = TracedNode::FromLocation(*from);
DCHECK(from_node->IsInUse());
TracedNode* to_node = TracedNode::FromLocation(*to); TracedNode* to_node = TracedNode::FromLocation(*to);
GlobalHandles* global_handles = nullptr; GlobalHandles* global_handles = nullptr;
#ifdef DEBUG
global_handles = GlobalHandles::From(from_node);
#endif // DEBUG
bool from_on_stack = from_node->is_on_stack(); bool from_on_stack = from_node->is_on_stack();
bool to_on_stack = false; bool to_on_stack = false;
if (!to_node) { if (!to_node) {
...@@ -980,6 +1009,8 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) { ...@@ -980,6 +1009,8 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) {
global_handles = GlobalHandles::From(from_node); global_handles = GlobalHandles::From(from_node);
to_on_stack = global_handles->on_stack_nodes_->IsOnStack( to_on_stack = global_handles->on_stack_nodes_->IsOnStack(
reinterpret_cast<uintptr_t>(to)); reinterpret_cast<uintptr_t>(to));
} else {
to_on_stack = to_node->is_on_stack();
} }
// Moving a traced handle with finalization callback is prohibited because // Moving a traced handle with finalization callback is prohibited because
...@@ -1005,16 +1036,17 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) { ...@@ -1005,16 +1036,17 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) {
to_node = TracedNode::FromLocation(*to); to_node = TracedNode::FromLocation(*to);
DCHECK(to_node->markbit()); DCHECK(to_node->markbit());
} else { } else {
// To node already exists, just copy fields. DCHECK(to_node->IsInUse());
*TracedNode::FromLocation(*to) = *from_node; to_node->CopyObjectReference(*from_node);
// Fixup back reference for destructor. if (!to_node->is_on_stack() && !to_node->is_in_young_list() &&
if (to_node->has_destructor()) { ObjectInYoungGeneration(to_node->object())) {
to_node->set_parameter(to); global_handles = GlobalHandles::From(from_node);
global_handles->traced_young_nodes_.push_back(to_node);
to_node->set_in_young_list(true);
} }
} }
DestroyTraced(*from); DestroyTraced(*from);
*from = nullptr; *from = nullptr;
to_node->Verify();
} else { } else {
// Pure heap move. // Pure heap move.
DestroyTraced(*to); DestroyTraced(*to);
...@@ -1028,8 +1060,8 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) { ...@@ -1028,8 +1060,8 @@ void GlobalHandles::MoveTracedGlobal(Address** from, Address** to) {
to_node->set_parameter(to); to_node->set_parameter(to);
} }
*from = nullptr; *from = nullptr;
to_node->Verify();
} }
TracedNode::Verify(global_handles, to);
} }
// static // static
......
This diff is collapsed.
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