| 1 | Improving the DOM |
| 2 | |
| 3 | - Take advantage of having one JS engine instead of two. Avoid abstractions, and target JSC directly. |
| 4 | - In some DOM functions when we update layout, we don't have to update the entire layout, in order to get results. |
| 5 | - For example, calling offsetWidth. We can layout just the block in question, rather than forcing a full layout. |
| 6 | - There seem to be many opportunities where JSC can help us figure out what information is really needed. |
| 7 | |
| 8 | Ideas? |
| 9 | - Get rid of DOM wrappers, essentially make DOM objects itself the wrapper. Seemed pretty straightforward to do, and eliminate a lot of indirection. |
| 10 | - How big is a wrapper object? A few pointers. |
| 11 | - If there's any data in a DOM node or HTML element that you'd like to move to the JS object because it's only accessed through DOM APIs, it is easy to do. |
| 12 | - DOM wrapper objects are just C++; they behave and run destructors correctly. Allocation is easy as well. Single VM is global; don't need to figure out which VM to use. |
| 13 | - One caveat: many wrappers are currently defined by IDL. So in order to define custom C++ data members, we need to invent a way to specify that. How about an IDL extension? |
| 14 | |
| 15 | - Are there things that are only accessed through DOM bindings, and not in other ways? |
| 16 | - Almost anything that you access through bindings originally comes from information otherwise produced by the engine. |
| 17 | |
| 18 | - Things we can move into the bindings, because they are only needed by wrappers. Or is it just stuff that needs fast access? |
| 19 | - Accessing document through window? Thought there was a fast path for this already. |
| 20 | - Node.parent; pull the wrapper directly into the object. Similar for children APIs. Potentially reduce multiple indirections. |
| 21 | |
| 22 | - Approach #1 (current): JS wrappers are not connected; have to jump between JS and C++. |
| 23 | - Approach #2: Have linkage in JS. No indirections. Make C++ traversal more expensive. |
| 24 | - Approach #3: Combine into one object so you don't have separate entities. |
| 25 | - Cannot copy because each isolated world has its own wrapper. This is a problem that just needs to be solved? You could make the DOM wrapper look isolated. |
| 26 | - Whole DOM has to be constructed out of GC'ed objects. GC allocator likely to be slower than just allocating+ref counting? Allocation churn in a GC heap is faster. |
| 27 | - Downside of going with WebCore GC objects is you're doubling the footprint. |
| 28 | - We don't know how to predict performance with GC tracking vs ref churning. Need to experiment. Try turning off ref counting (essentially, let everything leak) and see how that affects page loads. If that makes it significantly faster, that's a good data point. What is the size of the average DOM against the size of the JS heap? |
| 29 | - Approach #4: Delay creation of the wrapper until needed? |
| 30 | |
| 31 | - What about having smaller, separate objects from DOM objects? Start moving to a tighter, internal DOM. |
| 32 | - Take stuff in Node and Element base classes and move variables to separate classes. |
| 33 | - Move tree structure out. |
| 34 | - Node/Element are very large, and expose everything needed by the DOM; forces the need of a lot of pointers. We cannot use more efficient structures. |
| 35 | - Proposal is to have a "CoreNode" class, with a 1:1 mapping between Node and CoreNode. Optimize out parent node. If you actually access the DOM node then you instantiate it. |
| 36 | - If we decide to have the parent node in the internal DOM node, the main optimization would be to have a vector for next/prev siblings. |
| 37 | - But even with just that, we can do a lot of other optimizations. More than half of all nodes are text nodes; 40% of text nodes contain newline character. |
| 38 | - Biggest win is the locality of sibling elements. |
| 39 | |
| 40 | - How common does a node have a wrapper? It depends too much on the page. |
| 41 | - Some cases the malloc heap size is much larger than JS heap size. |
| 42 | - Some cases the node-to-wrapper ratio is very close to 1:1. |
| 43 | |
| 44 | - Our DOM class definitions are preventing us from being able to optimize for speed and memory. |
| 45 | - How about not creating text nodes at all? How about representing them as strings? This is very difficult to do. |
| 46 | - Eliminate semantic-free nodes like divs and spans? RenderObjects start talking to CoreNodes. |
| 47 | |
| 48 | - Approach #5: De-wrappify everything aggressively? DOM node was also the JS object, all allocated in JS heap, and we did parent+index trick instead of next and previous. |
| 49 | - Pros: Fast traversal (accessing array to get to children); lose ref counting churn; allocation is faster; ensure locality on GC end |
| 50 | |
| 51 | Proposal: |
| 52 | - All children are in a flat array. Make operations that traverse the tree much faster. |
| 53 | - Antti has a prototype of this! CoreNodes are all a fixed size. |
| 54 | - Possible to teach FastMalloc to allocate optimized for DOM? Using an arena would assist in his. |