Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(122)

Side by Side Diff: third_party/WebKit/Source/bindings/core/v8/TraceWrapperReference.md

Issue 2851563004: Add documentation for platform/bindings (Closed)
Patch Set: Code review Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Wrapper Tracing Reference
2
3 This document describes wrapper tracing and how its API is supposed to be used.
4
5 [TOC]
6
7 ## Quickstart guide
8
9 Wrapper tracing is used to represent reachability across V8 and Blink. The
10 following checklist highlights the modifications needed to make a class
11 participate in wrapper tracing.
12
13 1. Make sure that objects participating in tracing either inherit from
14 ``ScriptWrappable`` (if they can reference wrappers) or ``TraceWrapperBase``
15 (transitively holding wrappers alive).
16 2. Use ``TraceWrapperMember<T>`` to annotate fields that need to be followed to
17 find other wrappers that this object should keep alive.
18 3. Use ``TraceWrapperV8Reference<T>`` to annotate references to V8 that this
19 object should keep alive.
20 4. Declare a method to trace other wrappers using
21 ``DECLARE_VIRTUAL_TRACE_WRAPPERS()``.
22 5. Define the method using ``DEFINE_TRACE_WRAPPERS(ClassName)``.
23 6. Trace all fields that received a wrapper tracing type in (1) and (2) using
24 ``visitor->traceWrapers(<m_field>)`` in the body of ``DEFINE_TRACE_WRAPPERS``.
25
26 The following example illustrates these steps:
27
28 ```c++
29 #include "bindings/core/v8/ScriptWrappable.h"
30 #include "bindings/core/v8/TraceWrapperMember.h"
31 #include "bindings/core/v8/TraceWrapperV8Reference.h"
32
33 class SomeDOMObject : public ScriptWrappable { // (1)
34 public:
35 DECLARE_VIRTUAL_TRACE_WRAPPERS(); // (4)
36
37 private:
38 TraceWrapperMember<OtherWrappable> m_otherWrappable; // (2)
39 Member<NonWrappable> m_nonWrappable;
40 TraceWrapperV8Reference<v8::Value> m_v8object; // (3)
41 // ...
42 };
43
44 DEFINE_TRACE_WRAPPERS(SomeDOMObject) { // (5)
45 visitor->traceWrappers(m_otherWrappable); // (6)
46 visitor->traceWrappers(m_v8object); // (6)
47 }
48 ```
49
50 For more in-depth information and how to deal with corner cases continue on read ing.
51
52 ## Background
53
54 Blink and V8 need to cooperate to collect JavaScript *wrappers*. Each V8
55 *wrapper* object (*W*) in JavaScript is assigned a C++ *DOM object* (*D*) in
56 Blink. A single C++ *DOM object* can hold onto one or many *wrapper* objects.
57 During a garbage collection initiated from JavaScript, a *wrapper* then keeps
58 the C++ *DOM object* and all its transitive dependencies, including other
59 *wrappers*, alive, effectively tracing paths like
60 *W<sub>x</sub> -> D<sub>1</sub> -> ⋯ -> D<sub>n</sub> -> W<sub>y</sub>*.
61
62 Previously, this relationship was expressed using so-called object groups,
63 effectively assigning all C++ *DOM objects* in a given DOM tree the same group.
64 The group would only die if all objects belonging to the same group die. A brief
65 introduction on the limitations on this approach can be found in
66 [this slide deck][object-grouping-slides].
67
68 Wrapper tracing solves this problem by determining liveness based on
69 reachability by tracing through the C++ *DOM objects*. The rest of this document
70 describes how the API is used to keep JavaScript wrapper objects alive.
71
72 Note that *wrappables* have to be *on-heap objects* and thus all
73 [Oilpan-related rules][oilpan-docs] apply.
74
75 [object-grouping-slides]: https://docs.google.com/presentation/d/1I6leiRm0ysSTqy 7QWh33Gfp7_y4ngygyM2tDAqdF0fI/
76 [oilpan-docs]: https://chromium.googlesource.com/chromium/src/+/master/third_par ty/WebKit/Source/platform/heap/BlinkGCAPIReference.md
77
78 ## Basic usage
79
80 The annotations that are required can be found in the following header files.
81 Pick the header file depending on what types are needed.
82
83 ```c++
84 #include "bindings/core/v8/ScriptWrappable.h"
85 #include "bindings/core/v8/TraceWrapperBase.h"
86 #include "bindings/core/v8/TraceWrapperMember.h"
87 #include "bindings/core/v8/TraceWrapperV8Reference.h"
88 ```
89
90 The following example will guide through the modifications that are needed to
91 adjust a given class ``SomeDOMObject`` to participate in wrapper tracing.
92
93 ```c++
94 class SomeDOMObject : public ScriptWrappable {
95 // ...
96 private:
97 Member<OtherWrappable /* extending ScriptWrappable */> m_otherWrappable;
98 Member<NonWrappable> m_nonWrappable;
99 };
100 ```
101
102 In this scenario ``SomeDOMObject`` is the object that is wrapped by an object on
103 the JavaScript side. The next step is to identify the paths that lead to other
104 wrappables. In this case, only ``m_otherWrappable`` needs to be traced to find
105 other *wrappers* in V8.
106
107 As wrapper tracing only traces a subset of members residing on the Oilpan heap,
108 it requires its own tracing method. The macros are as follows:
109
110 * ``DECLARE_VIRTUAL_TRACE_WRAPPERS();``: Use in the class declaration to declare
111 the needed wrapper tracing method.
112 * ``DEFINE_TRACE_WRAPPERS(ClassName)``: Use to define the implementation of
113 wrapper tracing.
114
115 Many more convenience wrappers, like inline definitions, can be found in
116 ``platform/heap/WrapperVisitor.h``.
117
118 ```c++
119 class SomeDOMObject : public ScriptWrappable {
120 public:
121 DECLARE_VIRTUAL_TRACE_WRAPPERS();
122
123 private:
124 Member<OtherWrappable> m_otherWrappable;
125 Member<NonWrappable> m_nonWrappable;
126 };
127
128 DEFINE_TRACE_WRAPPERS(SomeDOMObject) {
129 visitor->traceWrappers(m_otherWrappable);
130 }
131 ```
132
133
134 Blink and V8 implement *incremental* wrapper tracing, which means that marking
135 can be interleaved with JavaScript or even DOM operations. This poses a
136 challenge, because already marked objects will not be considered again if they
137 are reached through some other path.
138
139 For example, consider an object ``A`` that has already been marked and a write
140 to a field ``A.x`` setting ``x`` to an unmarked object ``Y``. Since ``A.x`` is
141 the only reference keeping ``Y``, and ``A`` has already been marked, the garbage
142 collector will not find ``Y`` and reclaim it.
143
144 To overcome this problem we require all writes of interesting objects, i.e.,
145 writes to traced fields, to go through a write barrier. Repeat for simpler
146 readers: The write barrier will check for the problem case above and make sure
147 ``Y`` will be marked. In order to automatically issue a write barrier
148 ``m_otherWrappable`` needs ``TraceWrapperMember`` type.
149
150 ```c++
151 class SomeDOMObject : public ScriptWrappable {
152 public:
153 SomeDOMObject() : m_otherWrappable(this, nullptr) {}
154 DECLARE_VIRTUAL_TRACE_WRAPPERS();
155
156 private:
157 TraceWrapperMember<OtherWrappable> m_otherWrappable;
158 Member<NonWrappable> m_nonWrappable;
159 };
160
161 DEFINE_TRACE_WRAPPERS(SomeDOMObject) {
162 visitor->traceWrappers(m_otherWrappable);
163 }
164 ```
165
166 ``TraceWrapperMember`` makes sure that any write to ``m_otherWrappable`` will
167 consider doing a write barrier. Using the proper type, the write barrier is
168 correct by construction, i.e., it will never be missed.
169
170 ## Heap collections
171
172 The proper type usage for collections, e.g. ``HeapVector`` looks like the
173 following.
174
175 ```c++
176 class SomeDOMObject : public ScriptWrappable {
177 public:
178 // ...
179 void AppendNewValue(OtherWrappable* newValue);
180 DECLARE_VIRTUAL_TRACE_WRAPPERS();
181
182 private:
183 HeapVector<TraceWrapperMember<OtherWrappable>> m_otherWrappables;
184 };
185
186 DEFINE_TRACE_WRAPPERS(SomeDOMObject) {
187 for (auto other : m_otherWrappables)
188 visitor->traceWrappers(other);
189 }
190 ```
191
192 Note that this is different to Oilpan which can just trace the whole collection.
193 Whenever an element is added through ``append()`` the value needs to be
194 constructed using ``TraceWrapperMember``, e.g.
195
196 ```c++
197 void SomeDOMObject::AppendNewValue(OtherWrappable* newValue) {
198 m_otherWrappables.append(TraceWrapperMember(this, newValue));
199 }
200 ```
201
202 The compiler will throw an error for each ommitted ``TraceWrapperMember``
203 construction.
204
205 ### Corner-case: Pre-sized containers
206
207 Containers know how to construct an empty ``TraceWrapperMember`` slot. This
208 allows simple creation of containers at the cost of loosing the compile-time
209 check for assigning a raw value.
210
211 ```c++
212 class SomeDOMObject : public ScriptWrappable {
213 public:
214 SomeDOMObject() {
215 m_otherWrappables.resize(5);
216 }
217
218 void writeAt(int i, OtherWrappable* other) {
219 m_otherWrappables[i] = other;
220 }
221
222 DECLARE_VIRTUAL_TRACE_WRAPPERS();
223 private:
224 HeapVector<TraceWrapperMember<OtherWrappable>> m_otherWrappables;
225 };
226
227 DEFINE_TRACE_WRAPPERS(SomeDOMObject) {
228 for (auto other : m_otherWrappables)
229 visitor->traceWrappers(other);
230 }
231 ```
232
233 In this example, the compiler will not warn you on
234 ``m_otherWrappables[i] = other``, but an assertion will throw at runtime as long
235 as there exists a test covering that branch.
236
237 The correct assignment looks like
238
239 ```c++
240 m_otherWrappables[i] = TraceWrapperMember<OtherWrappable>(this, other);
241 ```
242
243 Note that the assertion that triggers when the annotation is not present does
244 not require wrapper tracing to be enabled.
245
246 ## Tracing through non-``ScriptWrappable`` types
247
248 Sometimes it is necessary to trace through types that do not inherit from
249 ``ScriptWrappable``. For example, consider the object graph
250 ``A -> B -> C`` where both ``A`` and ``C`` are ``ScriptWrappable``s that
251 need to be traced.
252
253 In this case, the same rules as with ``ScriptWrappables`` apply, except for the
254 difference that these classes need to inherit from ``TraceWrapperBase``.
255
256 ### Memory-footprint critical uses
257
258 In the case we cannot afford inheriting from ``TraceWrapperBase``, which will
259 add a vtable pointer for tracing wrappers, use
260 ``DEFINE_TRAIT_FOR_TRACE_WRAPPERS(ClassName)`` after defining
261 ``ClassName`` to define the proper tracing specializations.
262
263 ## Explicit write barriers
264
265 Sometimes it is necessary to stick with the regular types and issue the write
266 barriers explicitly. For example, if memory footprint is really important and
267 it's not possible to use ``TraceWrapperMember`` which adds another pointer
268 field. In this case, tracing needs to be adjusted to tell the system that all
269 barriers will be done manually.
270
271 ```c++
272 class ManualWrappable : public ScriptWrappable {
273 public:
274 void setNew(OtherWrappable* newValue) {
275 m_otherWrappable = newValue;
276 SriptWrappableVisitor::writeBarrier(this, m_otherWrappable);
277 }
278
279 DECLARE_VIRTUAL_TRACE_WRAPPERS();
280 private:
281 Member<OtherWrappable>> m_otherWrappable;
282 };
283
284 DEFINE_TRACE_WRAPPERS(ManualWrappable) {
285 for (auto other : m_otherWrappables)
286 visitor->traceWrappersWithManualWriteBarrier(other);
287 }
288 ```
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698