summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/bindings/trace_wrapper_member.h
blob: d021dcc8977495983a2e9f582f29200f831de309 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_TRACE_WRAPPER_MEMBER_H_
#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_TRACE_WRAPPER_MEMBER_H_

#include "third_party/blink/renderer/platform/bindings/script_wrappable_marking_visitor.h"
#include "third_party/blink/renderer/platform/heap/heap_allocator.h"

namespace blink {

template <typename T>
class Member;

// TraceWrapperMember is used for Member fields that should participate in
// wrapper tracing, i.e., strongly hold a ScriptWrappable alive. All
// TraceWrapperMember fields must be traced in the class' |Trace| method.
template <class T>
class TraceWrapperMember : public Member<T> {
  DISALLOW_NEW();

 public:
  TraceWrapperMember() : Member<T>(nullptr) {}

  TraceWrapperMember(T* raw) : Member<T>(raw) {
    // We have to use a write barrier here because of in-place construction
    // in containers, such as HeapVector::push_back.
    ScriptWrappableMarkingVisitor::WriteBarrier(raw);
  }

  TraceWrapperMember(WTF::HashTableDeletedValueType x) : Member<T>(x) {}

  TraceWrapperMember(const TraceWrapperMember& other) { *this = other; }

  TraceWrapperMember& operator=(const TraceWrapperMember& other) {
    Member<T>::operator=(other);
    DCHECK_EQ(other.Get(), this->Get());
    ScriptWrappableMarkingVisitor::WriteBarrier(this->Get());
    return *this;
  }

  TraceWrapperMember& operator=(const Member<T>& other) {
    Member<T>::operator=(other);
    DCHECK_EQ(other.Get(), this->Get());
    ScriptWrappableMarkingVisitor::WriteBarrier(this->Get());
    return *this;
  }

  TraceWrapperMember& operator=(T* other) {
    Member<T>::operator=(other);
    DCHECK_EQ(other, this->Get());
    ScriptWrappableMarkingVisitor::WriteBarrier(this->Get());
    return *this;
  }

  TraceWrapperMember& operator=(std::nullptr_t) {
    // No need for a write barrier when assigning nullptr.
    Member<T>::operator=(nullptr);
    return *this;
  }
};

// Swaps two HeapVectors specialized for TraceWrapperMember. The custom swap
// function is required as TraceWrapperMember potentially requires emitting a
// write barrier.
template <typename T>
void swap(HeapVector<TraceWrapperMember<T>>& a,
          HeapVector<TraceWrapperMember<T>>& b) {
  // HeapVector<Member<T>> and HeapVector<TraceWrapperMember<T>> have the
  // same size and semantics.
  HeapVector<Member<T>>& a_ = reinterpret_cast<HeapVector<Member<T>>&>(a);
  HeapVector<Member<T>>& b_ = reinterpret_cast<HeapVector<Member<T>>&>(b);
  a_.swap(b_);
  if (ThreadState::IsAnyWrapperTracing() &&
      ThreadState::Current()->IsWrapperTracing()) {
    // If incremental marking is enabled we need to emit the write barrier since
    // the swap was performed on HeapVector<Member<T>>.
    for (auto item : a) {
      ScriptWrappableMarkingVisitor::WriteBarrier(item.Get());
    }
    for (auto item : b) {
      ScriptWrappableMarkingVisitor::WriteBarrier(item.Get());
    }
  }
}

// HeapVectorBacking<TraceWrapperMember<T>> need to map to
// HeapVectorBacking<Member<T>> for performing the swap method below.
template <typename T, typename Traits>
struct GCInfoTrait<HeapVectorBacking<TraceWrapperMember<T>, Traits>>
    : public GCInfoTrait<
          HeapVectorBacking<Member<T>, WTF::VectorTraits<Member<T>>>> {};

// Swaps two HeapVectors, one containing TraceWrapperMember and one with
// regular Members. The custom swap function is required as TraceWrapperMember
// potentially requires emitting a write barrier.
template <typename T>
void swap(HeapVector<TraceWrapperMember<T>>& a, HeapVector<Member<T>>& b) {
  // HeapVector<Member<T>> and HeapVector<TraceWrapperMember<T>> have the
  // same size and semantics. This cast and swap assumes that GCInfo for both
  // TraceWrapperMember and Member match in vector backings.
  HeapVector<Member<T>>& a_ = reinterpret_cast<HeapVector<Member<T>>&>(a);
  a_.swap(b);
  if (ThreadState::IsAnyWrapperTracing() &&
      ThreadState::Current()->IsWrapperTracing()) {
    // If incremental marking is enabled we need to emit the write barrier since
    // the swap was performed on HeapVector<Member<T>>.
    for (auto item : a) {
      ScriptWrappableMarkingVisitor::WriteBarrier(item.Get());
    }
  }
}

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_TRACE_WRAPPER_MEMBER_H_