Skip to content

Commit 4a85102

Browse files
perf: pre-declare position on footnote factories
Problem: the footnote handlers build footnoteReference and footnoteDefinition nodes as fresh literals, then mdast-util-from- markdown's enter() sets node.position afterwards. V8 treats that late assignment as a shape change, so each node walks through two hidden classes instead of one. Core nodes already avoid this by declaring position up front; without the same trick on extension nodes, GFM trees end up with mixed layouts and tree walks pay a polymorphic-dispatch cost. Goal: declare position on both footnote literals at construction so V8 keeps a single hidden class per node type. Changes: - lib/index.js: trailing position: undefined on the footnoteReference literal in enterFootnoteCall. - lib/index.js: trailing position: undefined on the footnoteDefinition literal in enterFootnoteDefinition. Notes: pairs with the matching core change in syntax-tree/mdast-util-from-markdown#53; merged on its own this branch is a no-op. Validated with npm test (build, format, 100% coverage, 22 of 22 tests in dev and prod). Bench (local harness, 3-run median-of-medians, GFM tokenizer and mdast extensions stacked). Numbers below are the parse time delta versus an unmodified upstream main; positive numbers mean slower, negative numbers mean faster. Input: a document with 1000 footnote definitions and 1000 references to them. On the baseline this scenario carries a modest mdast-layer share (full 78.0 ms, tokenize-only 62.4 ms) but every footnote node still pays the shape-change cost without the pre-declare. Effect of pairing this branch with PR #53: - PR #53 alone, extensions on upstream main: 19.5 percent slower. - PR #53 with this branch alongside (and the three sibling extension branches): 13.0 percent slower, which sits at the upper end of the bench's drift floor of 4 to 12 percent (main vs main with no code change in the same window). The paired configuration recovers about 6.5 percentage points relative to PR #53 on its own. Without this branch, PR #53 would appear to regress footnote-heavy parses; with it, most of that apparent regression goes away.
1 parent 8ff7529 commit 4a85102

1 file changed

Lines changed: 16 additions & 2 deletions

File tree

lib/index.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,13 @@ function enterFootnoteCallString() {
3131
* @type {FromMarkdownHandle}
3232
*/
3333
function enterFootnoteCall(token) {
34-
this.enter({type: 'footnoteReference', identifier: '', label: ''}, token)
34+
// Trailing `position: undefined` keeps the footnoteReference hidden class
35+
// stable; mdast-util-from-markdown's enter() patches the field to a real
36+
// value but the property already exists, so no shape transition fires.
37+
this.enter(
38+
{type: 'footnoteReference', identifier: '', label: '', position: undefined},
39+
token
40+
)
3541
}
3642

3743
/**
@@ -47,8 +53,16 @@ function enterFootnoteDefinitionLabelString() {
4753
* @type {FromMarkdownHandle}
4854
*/
4955
function enterFootnoteDefinition(token) {
56+
// See enterFootnoteCall above for the rationale on the trailing
57+
// position field.
5058
this.enter(
51-
{type: 'footnoteDefinition', identifier: '', label: '', children: []},
59+
{
60+
type: 'footnoteDefinition',
61+
identifier: '',
62+
label: '',
63+
children: [],
64+
position: undefined
65+
},
5266
token
5367
)
5468
}

0 commit comments

Comments
 (0)