diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/bindings/DESIGN.md | 42 | ||||
-rw-r--r-- | components/script/dom/bindings/trace.rs | 8 | ||||
-rw-r--r-- | components/script/dom/mod.rs | 16 |
3 files changed, 15 insertions, 51 deletions
diff --git a/components/script/dom/bindings/DESIGN.md b/components/script/dom/bindings/DESIGN.md deleted file mode 100644 index 9ee7a50a7ac..00000000000 --- a/components/script/dom/bindings/DESIGN.md +++ /dev/null @@ -1,42 +0,0 @@ -# The design of Garbage collected DOM - -This is how Servo provides an object graph to SpiderMonkey's Garbage Collector. - -## Construct -When Servo creates a Rusty DOM object the binding code creates a corresponding wrapper `JSObject` with SpiderMonkey. It’s produced and set to the Rusty object in `FooBinding::Wrap`. - -In `FooBinding::Wrap`, the wrapper `JSObject` gets the pointer for the Rusty object to itself. At the same time the wrapper `JSObject` is set to the Rusty object’s `Reflector` field (all Rusty DOM objects have `dom::bindings::utils::Reflector` in their most basic fields). These steps are the “binding” work necessary to create the relationship between both objects. - - -## Trace object graph from SpiderMonkey GC -This is a tricky mechanism done with the help of the Rust compiler. -The outline is: - -1. SpiderMonkey's GC calls `JSClass.trace` defined in `FooBinding` during the marking phase. This `JSClass` is the basis of each wrapper `JSObject`. -2. `JSClass.trace` calls `Foo::trace()` (an implementation of `JSTraceable`). - This is typically derived via a #[jstraceable] annotation. -3. For all fields, `Foo::trace()` - calls `trace()` on the field. For example, for fields of type `JS<T>`, `JS<T>::trace()` calls - `trace_reflector()`. Non-JS-managed types have an empty inline `trace()` method, achieved via `no_jsmanaged_fields!` or similar. -4. `trace_reflector()` fetches the reflector that is reachable from a Rust object and notifies it to the GC using JSTracer. -5. This operation continues for the rest of the graph. -6. Finally, the GC checks whether the Rust object lives or not from `JSObject`s which are held by Rust object. - - -## Destruct -When destructing DOM objects (wrapper JSObjects), SpiderMonkey calls the `JSClass.finalize()` which is basis of each wrapper `JSObject`. This method refers to `FooBinding::_finalize()`. - -In the `_finalize()` function the pointer of the Rusty DOM object that is contained in the JSObject is unwrapped. It is then cast to a Rust owned pointer and assigned to an empty local variable. Thus we can destruct the Rusty object afterwards. - - -## Interact with Exact GC’s rooting -For supporting SpiderMonkey’s exact GC rooting, we introduce [some types](https://github.com/mozilla/servo/wiki/Using-DOM-types): - -- `JS<T>` is used for the DOM typed field in a DOM type structure. The GC can trace them recursively while the enclosing DOM object (maybe root) is alive. - - `LayoutJS<T>` is specialized `JS<T>` to use in layout. `Layout*Helper` must be implemented on this type to prevent calling methods from non layout code. -- `Unrooted<T>` is used to wrap raw pointers to DOM objects extracted from their reflectors. -- `Temporary<T>` is used as a return value for functions returning a DOM type. They are rooted for the duration of their lifetime. But a retun value gets moved around which can break the LIFO ordering constraint. Thus we need to introduce `Root<T>`. -- `Root<T>` contains the pointer to `JSObject` which the represented DOM type has. SpiderMonkey's conservative stack scanner scans it's pointers and marks a pointed `JSObject` as GC root. -- `JSRef` is just a reference to the value rooted by `Root<T>`. -- `RootCollection` is used to dynamically check if rooting satisfies LIFO ordering, because SpiderMonkey's GC requires LIFO order (See also: [Exact Stack Rooting - Storing a GCPointer on the CStack](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Internals/GC/Exact_Stack_Rooting)). - - `MutHeap<T>` is a version of `Cell<T>` that is safe to use for internal mutability of Spidermonkey heap objects like `JSVal` and `JS<T>` diff --git a/components/script/dom/bindings/trace.rs b/components/script/dom/bindings/trace.rs index 0eca6f00a14..e447b4c6a67 100644 --- a/components/script/dom/bindings/trace.rs +++ b/components/script/dom/bindings/trace.rs @@ -12,7 +12,9 @@ //! phase. (This happens through `JSClass.trace` for non-proxy bindings, and //! through `ProxyTraps.trace` otherwise.) //! 2. `_trace` calls `Foo::trace()` (an implementation of `JSTraceable`). -//! This is typically derived via a #[jstraceable] annotation +//! This is typically derived via a `#[dom_struct]` (implies `#[jstraceable]`) annotation. +//! Non-JS-managed types have an empty inline `trace()` method, +//! achieved via `no_jsmanaged_fields!` or similar. //! 3. For all fields, `Foo::trace()` //! calls `trace()` on the field. //! For example, for fields of type `JS<T>`, `JS<T>::trace()` calls @@ -21,8 +23,10 @@ //! reflector. //! 5. `trace_object()` calls `JS_CallTracer()` to notify the GC, which will //! add the object to the graph, and will trace that object as well. +//! 6. When the GC finishes tracing, it [`finalizes`](../index.html#destruction) +//! any reflectors that were not reachable. //! -//! The no_jsmanaged_fields!() macro adds an empty implementation of JSTraceable to +//! The `no_jsmanaged_fields!()` macro adds an empty implementation of `JSTraceable` to //! a datatype. use dom::bindings::js::JS; diff --git a/components/script/dom/mod.rs b/components/script/dom/mod.rs index 0650a900494..6a9b4827e96 100644 --- a/components/script/dom/mod.rs +++ b/components/script/dom/mod.rs @@ -67,10 +67,10 @@ //! (The result of either method can be wrapped in `Result`, if that is //! appropriate for the type in question.) //! -//! The latter calls the former, boxes the result, and creates a reflector for -//! it by calling `dom::bindings::utils::reflect_dom_object` (which yields -//! ownership of the object to the SpiderMonkey Garbage Collector). This is the -//! API to use when creating a DOM object. +//! The latter calls the former, boxes the result, and creates a reflector +//! corresponding to it by calling `dom::bindings::utils::reflect_dom_object` +//! (which yields ownership of the object to the SpiderMonkey Garbage Collector). +//! This is the API to use when creating a DOM object. //! //! The former should only be called by the latter, and by subclasses' //! `new_inherited` methods. @@ -98,9 +98,11 @@ //! ============================= //! //! Every DOM object has a `Reflector` as its first (transitive) member field. -//! This contains a `*mut JSObject` that points to its reflector. This field -//! is initialized by the `FooBinding::Wrap` method, called from -//! `reflect_dom_object`. +//! This contains a `*mut JSObject` that points to its reflector. +//! +//! The `FooBinding::Wrap` function creates the reflector, stores a pointer to +//! the DOM object in the reflector, and initializes the pointer to the reflector +//! in the `Reflector` field. //! //! The `Reflectable` trait provides a `reflector()` method that returns the //! DOM object's `Reflector`. It is implemented automatically for DOM structs |