Changes between Version 1 and Version 2 of JSRootingGuide


Ignore:
Timestamp:
Jun 21, 2014, 8:55:25 PM (10 years ago)
Author:
Yves
Comment:

Adds a basic description of the different heap rooting approaches

Legend:

Unmodified
Added
Removed
Modified
  • JSRootingGuide

    v1 v2  
    2121}}}
    2222
     23
     24== Heap rooting ==
     25Rooting on the heap is much different than rooting on the stack. On the stack, new rooted types (like JS::Rooted<T>) are always constructed and destructed in LIFO order. This behaviour gets used for optimization in is essential for all types used for rooting on the stack. Data on the heap can be rooted and unrooted in arbitrary order and needs different types and different approaches.
     26
     27The following sections are an attempt to describe the important differences as well as advantages and disadvantages of the available heap rooting approaches.
     28
     29=== The JS::Heap<T> type ===
     30Wrapping the value in JS::Heap<T> only protects the pointer from becoming invalid when the GC thing it points to gets moved (moving GC).
     31It does not protect the GC thing from being collected by the GC! This type always has to be used in combination with a rooting approach that protects against GC!
     32
     33=== Using JS::Heap<T>, JS::Add*Root and JS::Remove*Root ===
     34Using JS::Add*Root is one way of protecting a GC thing from being collected. Later there needs to be a call to JS::Remove*Root to enable collection again.
     35I haven't yet figured out a clear advantage of this approach compared to the other two approaches. It looks like this approach gets used rarely in Firefox and they are replacing it in favour of the other two approaches.
     36
     37TODO: are they going to remove it from the API? Are there use cases where this rooting approach is superior?
     38
     39Characteristics:
     40 * If no RAII approach is used, it can easily cause leaks if the call to Remove*Root() is missing.
     41 * In some Gecko use cases this can't be used because it can cause cycles and the cycle collector won't know about them (this is not relevant for us because we don't need a cycle collector).
     42 * It bloats up the root set. --> What does this mean in practice?
     43 * Add*Root is slow --> What does this mean in practice?
     44
     45Guideline:
     46 * Try to use the other approaches for the moment. We still have to figure out when/if this approach should be used.
     47
     48=== Using JS::Heap<T> in combination with custom tracers ===
     49Implementing tracers and adding them via JS_AddExtraGCRootsTracer is one way of protecting against GC. Each tracer that gets added needs to be removed again later with JS_RemoveExtraGCRootsTracer.
     50
     51Note: There are other ways to add a specified trace function (I haven't tested those yet).
     52
     53Characteristics:
     54 * Obviously it's faster to add (and later remove) one function that gets called during GC and loops over many objects than adding (and removing) many objects to the GC root set in a loop.
     55 * Less memory overhead because storing a pointer to a trace function requires less memory than storing a large number of pointers to GC things.
     56
     57Guideline:
     58 * This approach should be used if large numbers of GC things need to be rooted.
     59
     60=== Using JS::!PersistentRooted<T> ===
     61
     62Characteristics:
     63 * This type both keeps the reference to the GC thing valid when it gets moved and it protects it against garbage collection.
     64 * Costs a small memory and CPU performance overhead (stores GC things to be rooted in a linked list internally).
     65 * It's obviously easier to use, the code looks cleaner and it's less error prone.
     66
     67Guideline:
     68 * This approach should be used for small numbers of objects that don't get rooted and unrooted often.
     69