| 1 | = DOM Bindings, Event Loop & More |
| 2 | ''by Ryosuke Niwa'' |
| 3 | |
| 4 | - C++ and JS Objects |
| 5 | - C++ objects define behavior |
| 6 | - JS wrappers expose them to JavaScript |
| 7 | - Injected scripts have their own DOM wrapper “world” |
| 8 | - Converting Objects |
| 9 | - toJS(node) to get a JS wrapper |
| 10 | - toWrapped(node) / jsNode.wrapped() to get C++ object |
| 11 | - Cache main world’s wrapper via ScriptWrappable |
| 12 | - When should we use it? |
| 13 | - Use it when performance matters |
| 14 | - Cost is one extra object; memory concern |
| 15 | - Wrapped object is always fast |
| 16 | - Lifecycle of DOM Objects |
| 17 | - JS wrapper keeps C++ object alive |
| 18 | - Ref<> in JSDOMWrapper |
| 19 | - Two ways to keep JS wrappers alive |
| 20 | - Visit children |
| 21 | - Reachable from Opaque Roots |
| 22 | - Visit children? Implement visitChildren function and do something? |
| 23 | - Yes |
| 24 | - Inspector GC heap, you can look at it in Web Inspector |
| 25 | - Common misconception |
| 26 | - C++ objects do NOT keep their JS wrappers alive by default |
| 27 | class Some : RefCounted<Some> { |
| 28 | … |
| 29 | Ref<Other> m_other; // <<— JS other will still go away |
| 30 | } |
| 31 | class Other : RefCounted<Other> { } |
| 32 | - Lifecycle: Visit Children |
| 33 | - JSCustomMarkFunction in IDL |
| 34 | - Add JS*::visitAdditionalChildren in JS*Custom.cpp |
| 35 | - Visit JS object kept by WebCore |
| 36 | - Lifecycle: Opaque Roots |
| 37 | - GeneratelsReachable=Impl* or CustomlsReachable in IDL |
| 38 | - addOpaqueRoot in visitAdditionalChildren |
| 39 | - JS*::isReachableFromOpaqueRoots |
| 40 | - Lifecycle: Concurrency |
| 41 | - Visiting & opaque root checks happen in non-main threads |
| 42 | - Can’t make createWeakPtr or ref / deref RefCounted objects |
| 43 | - Cant lookup HashMap |
| 44 | - What ones run with the main thread stopped vs what runs when main thread is not stopped? |
| 45 | - VisitChildren runs when the main thread is running, runs on background threads when the main thread is not running |
| 46 | - IsOpaqueRoots stops the main thread and runs on background threads |
| 47 | - Lifecycle: Common Cases |
| 48 | - Keeping JS object alive → Visit Children |
| 49 | - Store JSC::Weak<JSC::JSObject> |
| 50 | - ActiveDOMCallback for callbacks |
| 51 | - C++ object relationship → Opaque Roots |
| 52 | - Agree on opaque root; typically root Node |
| 53 | - Write thread safe code to get opaque root |
| 54 | - Lifecycle: NodeLists |
| 55 | - Diagram |
| 56 | - Lifecycle: DOM Nodes |
| 57 | - Node is alive if it has refCount > 0 or has parent node |
| 58 | - Node increments Document’s m_referencingNodeCount |
| 59 | - Document is alive if refCount > 0 or m_referencingNodeCount > 0 |
| 60 | - Node::removedLastRef on Element |
| 61 | - ContainerNode::removeDetachedChildren in ~ContainerNode |
| 62 | - Turn into flat linked list in deletion queue |
| 63 | - Document::removedLastRef() must clear any Ref / RefPtr to Node |
| 64 | - Not safe to traverse DOM tree during destruction |
| 65 | - Node Insertion & Removal |
| 66 | - Node::insertedIntoAncestor / removedFromAncestor |
| 67 | - Called whenever node’s ancestor changes |
| 68 | - Either “this” or its ancestor got inserted or removed |
| 69 | - Don’t assume tree scope or document change |
| 70 | - No script execution in insertedIntoAncestor or removedFromAncestor |
| 71 | - Will hit release assertion |
| 72 | - Use didFinishInsertingNode instead |
| 73 | - Node Insertion Order |
| 74 | - insertedIntoAncestor called in tree order |
| 75 | - Only talk to nodes earlier in tree order |
| 76 | - Node Removal Order |
| 77 | - removedFromAncestor called in tree order |
| 78 | - Only talk to nodes earlier in tree order |
| 79 | - Run layout tests with --world-leaks |
| 80 | - Lifecycle: Delayed Use |
| 81 | - Asynchronous use of “this” - XHR, media, … |
| 82 | - Make “this” ActiveDOMObject |
| 83 | - Asynchronous use of Node - MutationObserver, ResizeObserver, … |
| 84 | - GCReachableRef ← This is a leak! |
| 85 | - Lifecycle: ActiveDOMObject |
| 86 | - Async work → dispatchEvent on this |
| 87 | - Reachable if hasPendingActivity is true |
| 88 | - Suspendable for back-forward cache |
| 89 | - HTML5 Event Loop |
| 90 | - WindowEventLoop has been added |
| 91 | - WorkerEventLoop is coming |
| 92 | - WindowEventLoop is shared across documents of similar origins |
| 93 | - Event Loop: In New Code |
| 94 | - Do NOT USE |
| 95 | - Timer / SuspendableTimer |
| 96 | - GenericEventQueue / GenericTaskQueue |
| 97 | |
| 98 | ''(rniwa is a genius. officially.)'' |