summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/bindings/TraceWrapperReference.md
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/bindings/TraceWrapperReference.md')
-rw-r--r--chromium/third_party/blink/renderer/platform/bindings/TraceWrapperReference.md176
1 files changed, 70 insertions, 106 deletions
diff --git a/chromium/third_party/blink/renderer/platform/bindings/TraceWrapperReference.md b/chromium/third_party/blink/renderer/platform/bindings/TraceWrapperReference.md
index 23adab6a7ab..d8b0b2c2aac 100644
--- a/chromium/third_party/blink/renderer/platform/bindings/TraceWrapperReference.md
+++ b/chromium/third_party/blink/renderer/platform/bindings/TraceWrapperReference.md
@@ -1,52 +1,45 @@
# Wrapper Tracing Reference
This document describes wrapper tracing and how its API is supposed to be used.
+Note that wrapper tracing is based on Oilpan garbage collection infrastructure, which makes [Oilpan's documentation][oilpan-docs] a good first read.
[TOC]
## Quickstart guide
-Wrapper tracing is used to represent reachability across V8 and Blink. The
-following checklist highlights the modifications needed to make a class
-participate in wrapper tracing.
-
-1. Make sure that objects participating in tracing either inherit from
-`ScriptWrappable` (if they can reference wrappers) or `TraceWrapperBase`
-(transitively holding wrappers alive).
-2. Use `TraceWrapperMember<T>` to annotate fields that need to be followed to
-find other wrappers that this object should keep alive.
-3. Use `TraceWrapperV8Reference<T>` to annotate references to V8 that this
-object should keep alive.
-4. Declare a `virtual void TraceWrappers(ScriptWrappableVisitor*) const`
-method to trace other wrappers.
-5. Define the method and trace all fields that received a wrapper tracing type
-in (1) and (2) using `visitor->TraceWrappers(<field_>)` in the body.
+Wrapper tracing is used to represent reachability across V8 and Blink.
+The following checklist highlights the modifications needed to make a class participate in wrapper tracing.
+
+1. Make sure that objects participating in tracing either inherit from `ScriptWrappable` if they can reference wrappers or are otherwise part of Oilpan's heap, e.g. by making them inherit from `GarbageCollected` or one of its friends.
+2. Use `TraceWrapperMember<T>` to annotate fields that need to be followed to find other wrappers that this object should keep alive.
+3. Use `TraceWrapperV8Reference<T>` to annotate references to V8 that this object should keep alive.
+4. Make sure those fields are properly visited from `T::Trace`, similar to all other garbage collected types.
The following example illustrates these steps:
```c++
-#include "platform/bindings/ScriptWrappable.h"
-#include "platform/bindings/TraceWrapperMember.h"
-#include "platform/bindings/TraceWrapperV8Reference.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_member.h"
+#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
class SomeDOMObject : public ScriptWrappable { // (1)
DEFINE_WRAPPERTYPEINFO();
public:
- virtual void TraceWrappers(
- ScriptWrappableVisitor*) const; // (4)
+ void Trace(Visitor*) override;
private:
- TraceWrapperMember<OtherWrappable> other_wrappable_; // (2)
Member<NonWrappable> non_wrappable_;
+ TraceWrapperMember<OtherWrappable> other_wrappable_; // (2)
TraceWrapperV8Reference<v8::Value> v8object_; // (3)
// ...
};
-void SomeDOMObject::TraceWrappers(
- ScriptWrappableVisitor* visitor) const { // (5)
- visitor->TraceWrappers(other_wrappable_); // (5)
- visitor->TraceWrappers(v8object_); // (5)
+void SomeDOMObject::Trace(Visitor* visitor) {
+ visitor->Trace(non_wrappable_);
+ visitor->Trace(other_wrappable_); // (4)
+ visitor->Trace(v8object_); // (4)
+ ScriptWrappable::Trace(visitor);
}
```
@@ -54,26 +47,19 @@ For more in-depth information and how to deal with corner cases continue on read
## Background
-Blink and V8 need to cooperate to collect JavaScript *wrappers*. Each V8
-*wrapper* object (*W*) in JavaScript is assigned a C++ *DOM object* (*D*) in
-Blink. A single C++ *DOM object* can hold onto one or many *wrapper* objects.
-During a garbage collection initiated from JavaScript, a *wrapper* then keeps
-the C++ *DOM object* and all its transitive dependencies, including other
-*wrappers*, alive, effectively tracing paths like
-*W<sub>x</sub> -> D<sub>1</sub> -> ⋯ -> D<sub>n</sub> -> W<sub>y</sub>*.
+Blink and V8 need to cooperate to collect JavaScript *wrappers*.
+Each V8 *wrapper* object (*W*) in JavaScript is assigned a C++ *DOM object* (*D*) in Blink.
+A single C++ *DOM object* can hold onto one or many *wrapper* objects.
+During a garbage collection initiated from JavaScript, a *wrapper* then keeps the C++ *DOM object* and all its transitive dependencies, including other *wrappers*, alive, effectively tracing paths like *W<sub>x</sub> -> D<sub>1</sub> -> ⋯ -> D<sub>n</sub> -> W<sub>y</sub>*.
-Previously, this relationship was expressed using so-called object groups,
-effectively assigning all C++ *DOM objects* in a given DOM tree the same group.
-The group would only die if all objects belonging to the same group die. A brief
-introduction on the limitations on this approach can be found in
-[this slide deck][object-grouping-slides].
+Previously, this relationship was expressed using so-called object groups, effectively assigning all C++ *DOM objects* in a given DOM tree the same group.
+The group would only die if all objects belonging to the same group die.
+A brief introduction on the limitations on this approach can be found in [this slide deck][object-grouping-slides].
-Wrapper tracing solves this problem by determining liveness based on
-reachability by tracing through the C++ *DOM objects*. The rest of this document
-describes how the API is used to keep JavaScript wrapper objects alive.
+Wrapper tracing solves this problem by determining liveness based on reachability by tracing through the C++ *DOM objects*.
+The rest of this document describes how the API is used to keep JavaScript wrapper objects alive.
-Note that *wrappables* have to be *on-heap objects* and thus all
-[Oilpan-related rules][oilpan-docs] apply.
+Note that *wrappables* have to be part of Oilpan and thus all [Oilpan-related rules][oilpan-docs] apply.
[object-grouping-slides]: https://docs.google.com/presentation/d/1I6leiRm0ysSTqy7QWh33Gfp7_y4ngygyM2tDAqdF0fI/
[oilpan-docs]: https://chromium.googlesource.com/chromium/src/+/master/third_party/blink/renderer/platform/heap/BlinkGCAPIReference.md
@@ -88,108 +74,99 @@ Pick the header file depending on what types are needed.
#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h"
```
-The following example will guide through the modifications that are needed to
-adjust a given class `SomeDOMObject` to participate in wrapper tracing.
+The following example will guide through the modifications that are needed to adjust a given class `SomeDOMObject` to participate in wrapper tracing.
```c++
class SomeDOMObject : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
// ...
+
private:
Member<OtherWrappable /* extending ScriptWrappable */> other_wrappable_;
Member<NonWrappable> non_wrappable_;
};
```
-In this scenario `SomeDOMObject` is the object that is wrapped by an object on
-the JavaScript side. The next step is to identify the paths that lead to other
-wrappables. In this case, only `other_wrappable_` needs to be traced to find
-other *wrappers* in V8.
+In this scenario `SomeDOMObject` is the object that is wrapped by an object on the JavaScript side.
+The next step is to identify the paths that lead to other wrappables.
+In this case, only `other_wrappable_` needs to be traced to find other *wrappers* in V8.
```c++
class SomeDOMObject : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- virtual void TraceWrappers(ScriptWrappableVisitor*) const;
+ void Trace(Visitor*) override;
private:
Member<OtherWrappable> other_wrappable_;
Member<NonWrappable> non_wrappable_;
};
-void SomeDOMObject::TraceWrappers(
- ScriptWrappableVisitor* visitor) const {
- visitor->TraceWrappers(other_wrappable_);
+void SomeDOMObject::Trace(Visitor* visitor) {
+ visitor->Trace(other_wrappable_);
+ visitor->Trace(non_wrappable_);
+ ScriptWrappable::Trace(visitor);
}
```
+Blink and V8 implement *incremental* wrapper tracing, which means that marking can be interleaved with JavaScript or even DOM operations.
+This poses a challenge, because already marked objects will not be considered again if they are reached through some other path.
-Blink and V8 implement *incremental* wrapper tracing, which means that marking
-can be interleaved with JavaScript or even DOM operations. This poses a
-challenge, because already marked objects will not be considered again if they
-are reached through some other path.
-
-For example, consider an object `A` that has already been marked and a write
-to a field `A.x` setting `x` to an unmarked object `Y`. Since `A.x` is
-the only reference keeping `Y`, and `A` has already been marked, the garbage
-collector will not find `Y` and reclaim it.
+For example, consider an object `A` that has already been marked and a write to a field `A.x` setting `x` to an unmarked object `Y`.
+Since `A.x` is the only reference keeping `Y`, and `A` has already been marked, the garbage collector will not find `Y` and reclaim it.
-To overcome this problem we require all writes of interesting objects, i.e.,
-writes to traced fields, to go through a write barrier.
-The write barrier will check for the problem case above and make sure
-`Y` will be marked. In order to automatically issue a write barrier
-`other_wrappable_` needs `TraceWrapperMember` type.
+To overcome this problem we require all writes of interesting objects, i.e., writes to traced fields, to go through a write barrier.
+The write barrier will check for the problem case above and make sure `Y` will be marked.
+In order to automatically issue a write barrier `other_wrappable_` needs `TraceWrapperMember` type.
```c++
class SomeDOMObject : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- virtual void TraceWrappers(ScriptWrappableVisitor*) const;
+ void Trace(Visitor*) override;
private:
TraceWrapperMember<OtherWrappable> other_wrappable_;
Member<NonWrappable> non_wrappable_;
};
-void SomeDOMObject::TraceWrappers(
- ScriptWrappableVisitor* visitor) const {
- visitor->TraceWrappers(other_wrappable_);
+void SomeDOMObject::Trace(Visitor* visitor) {
+ visitor->Trace(other_wrappable_);
+ visitor->Trace(non_wrappable_);
+ ScriptWrappable::Trace(visitor);
}
```
-`TraceWrapperMember` makes sure that any write to `other_wrappable_` will
-consider doing a write barrier. Using the proper type, the write barrier is
-correct by construction, i.e., it will never be missed.
+`TraceWrapperMember` makes sure that any write to `other_wrappable_` will consider doing a write barrier.
+Using the proper type, the write barrier is correct by construction, i.e., it will never be missed.
## Heap collections
-The proper type usage for collections, e.g. `HeapVector` looks like the
-following.
+Wrapper tracing is integrated into Oilpan's support for collections, so there's no additional work needed other than making sure the collection is visited in the corresponding `Trace` method.
+The proper type usage for collections, e.g. `HeapVector` looks like the following.
```c++
class SomeDOMObject : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- // ...
+ void Trace(Visitor*) override;
+
void AppendNewValue(OtherWrappable* newValue);
- virtual void TraceWrappers(ScriptWrappableVisitor*) const;
private:
HeapVector<TraceWrapperMember<OtherWrappable>> other_wrappables_;
};
-void SomeDOMObject::TraceWrappers(
- ScriptWrappableVisitor* visitor) const {
- for (auto other : other_wrappables_)
- visitor->TraceWrappers(other);
+void SomeDOMObject::Trace(Visitor* visitor) {
+ visitor->Trace(other_wrappables_);
+ ScriptWrappable::Trace(visitor);
}
```
-Note that this is different to Oilpan which can just trace the whole collection.
`TraceWrapperMember` can be constructed in place, so using `append` and
friends will work out of the box, e.g.
@@ -199,9 +176,6 @@ void SomeDOMObject::AppendNewValue(OtherWrappable* newValue) {
}
```
-The compiler will throw an error for each omitted `TraceWrapperMember`
-construction.
-
### Swapping `HeapVector` containing `TraceWrapperMember` and `Member`
It is possible to swap two `HeapVectors` containing `TraceWrapperMember` and
@@ -222,44 +196,34 @@ blink::swap(c, temporary);
## Tracing through non-`ScriptWrappable` types
-Sometimes it is necessary to trace through types that do not inherit from
-`ScriptWrappable`. For example, consider the object graph
-`A -> B -> C` where both `A` and `C` are `ScriptWrappable`s that
-need to be traced.
+Sometimes it is necessary to trace through types that do not inherit from `ScriptWrappable`.
+For example, consider the object graph `A -> B -> C` where both `A` and `C` are `ScriptWrappable`s that need to be traced.
-In this case, the same rules as with `ScriptWrappables` apply, except for the
-difference that these classes need to inherit from `TraceWrapperBase`.
-
-### Memory-footprint critical uses
-
-In the case we cannot afford inheriting from `TraceWrapperBase`, which will
-add a vtable pointer for tracing wrappers, use
-`DEFINE_TRAIT_FOR_TRACE_WRAPPERS(ClassName)` after defining
-`ClassName` to define the proper tracing specializations.
+In this case, the same rules as with `ScriptWrappables` apply, except for the difference that these classes need to inherit from some other class that is managed by Oilpan, e.g. `GarbageCollected`.
## Explicit write barriers
-Sometimes it is necessary to stick with the regular types and issue the write
-barriers explicitly. In this case, tracing needs to be adjusted to tell the
-system that all barriers will be done manually.
+Sometimes it is necessary to stick with the regular types or raw pointers and issue the write barriers explicitly.
+In this case, tracing needs to be adjusted to tell the system that all barriers will be done manually.
```c++
class ManualWrappable : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();
public:
- void setNew(OtherWrappable* newValue) {
+ void Trace(Visitor*) override;
+
+ void SetNew(OtherWrappable* newValue) {
other_wrappable_ = newValue;
SriptWrappableVisitor::WriteBarrier(other_wrappable_);
}
- virtual void TraceWrappers(ScriptWrappableVisitor*) const;
private:
Member<OtherWrappable>> other_wrappable_;
};
-void ManualWrappable::TraceWrappers(
- ScriptWrappableVisitor* visitor) const {
- visitor->TraceWrappersWithManualWriteBarrier(other_wrappable_);
+void ManualWrappable::Trace(Visitor* visitor) {
+ visitor->TraceWithWrappers(other_wrappable_.Get());
+ ScriptWrappable::Trace(visitor);
}
```