| | 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.)'' |