Skip to content

Commit 0f8773f

Browse files
authored
Do less allocation in JSDoc parsing (#1280)
1 parent 9ec05e4 commit 0f8773f

File tree

6 files changed

+45
-37
lines changed

6 files changed

+45
-37
lines changed

internal/api/encoder/encoder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,7 @@ func recordNodeStrings(node *ast.Node, strs *stringTable) uint32 {
774774
case ast.KindNoSubstitutionTemplateLiteral:
775775
return strs.add(node.AsNoSubstitutionTemplateLiteral().Text, node.Kind, node.Pos(), node.End())
776776
case ast.KindJSDocText:
777-
return strs.add(node.AsJSDocText().Text, node.Kind, node.Pos(), node.End())
777+
return strs.add(node.AsJSDocText().Text(), node.Kind, node.Pos(), node.End())
778778
default:
779779
panic(fmt.Sprintf("Unexpected node kind %v", node.Kind))
780780
}

internal/ast/ast.go

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ func (n *Node) Text() string {
296296
case KindRegularExpressionLiteral:
297297
return n.AsRegularExpressionLiteral().Text
298298
case KindJSDocText:
299-
return n.AsJSDocText().Text
299+
return strings.Join(n.AsJSDocText().text, "")
300300
}
301301
panic(fmt.Sprintf("Unhandled case in Node.Text: %T", n.data))
302302
}
@@ -8814,40 +8814,40 @@ type JSDocTagBase struct {
88148814

88158815
type JSDocCommentBase struct {
88168816
NodeBase
8817-
Text string
8817+
text []string
88188818
}
88198819

88208820
// JSDoc comments
88218821
type JSDocText struct {
88228822
JSDocCommentBase
88238823
}
88248824

8825-
func (f *NodeFactory) NewJSDocText(text string) *Node {
8825+
func (f *NodeFactory) NewJSDocText(text []string) *Node {
88268826
data := f.jsdocTextPool.New()
8827-
data.Text = text
8827+
data.text = text
88288828
f.textCount++
88298829
return f.newNode(KindJSDocText, data)
88308830
}
88318831

88328832
func (node *JSDocText) Clone(f NodeFactoryCoercible) *Node {
8833-
return cloneNode(f.AsNodeFactory().NewJSDocText(node.Text), node.AsNode(), f.AsNodeFactory().hooks)
8833+
return cloneNode(f.AsNodeFactory().NewJSDocText(node.text), node.AsNode(), f.AsNodeFactory().hooks)
88348834
}
88358835

88368836
type JSDocLink struct {
88378837
JSDocCommentBase
88388838
name *Node // optional (should only be EntityName)
88398839
}
88408840

8841-
func (f *NodeFactory) NewJSDocLink(name *Node, text string) *Node {
8841+
func (f *NodeFactory) NewJSDocLink(name *Node, text []string) *Node {
88428842
data := &JSDocLink{}
88438843
data.name = name
8844-
data.Text = text
8844+
data.text = text
88458845
f.textCount++
88468846
return f.newNode(KindJSDocLink, data)
88478847
}
88488848

8849-
func (f *NodeFactory) UpdateJSDocLink(node *JSDocLink, name *Node, text string) *Node {
8850-
if name != node.name || text != node.Text {
8849+
func (f *NodeFactory) UpdateJSDocLink(node *JSDocLink, name *Node, text []string) *Node {
8850+
if name != node.name || !core.Same(text, node.text) {
88518851
return updateNode(f.NewJSDocLink(name, text), node.AsNode(), f.hooks)
88528852
}
88538853
return node.AsNode()
@@ -8858,11 +8858,11 @@ func (node *JSDocLink) ForEachChild(v Visitor) bool {
88588858
}
88598859

88608860
func (node *JSDocLink) VisitEachChild(v *NodeVisitor) *Node {
8861-
return v.Factory.UpdateJSDocLink(node, v.visitNode(node.name), node.Text)
8861+
return v.Factory.UpdateJSDocLink(node, v.visitNode(node.name), node.text)
88628862
}
88638863

88648864
func (node *JSDocLink) Clone(f NodeFactoryCoercible) *Node {
8865-
return cloneNode(f.AsNodeFactory().NewJSDocLink(node.Name(), node.Text), node.AsNode(), f.AsNodeFactory().hooks)
8865+
return cloneNode(f.AsNodeFactory().NewJSDocLink(node.Name(), node.text), node.AsNode(), f.AsNodeFactory().hooks)
88668866
}
88678867

88688868
func (node *JSDocLink) Name() *DeclarationName {
@@ -8874,16 +8874,16 @@ type JSDocLinkPlain struct {
88748874
name *Node // optional (should only be EntityName)
88758875
}
88768876

8877-
func (f *NodeFactory) NewJSDocLinkPlain(name *Node, text string) *Node {
8877+
func (f *NodeFactory) NewJSDocLinkPlain(name *Node, text []string) *Node {
88788878
data := &JSDocLinkPlain{}
88798879
data.name = name
8880-
data.Text = text
8880+
data.text = text
88818881
f.textCount++
88828882
return f.newNode(KindJSDocLinkPlain, data)
88838883
}
88848884

8885-
func (f *NodeFactory) UpdateJSDocLinkPlain(node *JSDocLinkPlain, name *Node, text string) *Node {
8886-
if name != node.name || text != node.Text {
8885+
func (f *NodeFactory) UpdateJSDocLinkPlain(node *JSDocLinkPlain, name *Node, text []string) *Node {
8886+
if name != node.name || !core.Same(text, node.text) {
88878887
return updateNode(f.NewJSDocLinkPlain(name, text), node.AsNode(), f.hooks)
88888888
}
88898889
return node.AsNode()
@@ -8894,11 +8894,11 @@ func (node *JSDocLinkPlain) ForEachChild(v Visitor) bool {
88948894
}
88958895

88968896
func (node *JSDocLinkPlain) VisitEachChild(v *NodeVisitor) *Node {
8897-
return v.Factory.UpdateJSDocLinkPlain(node, v.visitNode(node.name), node.Text)
8897+
return v.Factory.UpdateJSDocLinkPlain(node, v.visitNode(node.name), node.text)
88988898
}
88998899

89008900
func (node *JSDocLinkPlain) Clone(f NodeFactoryCoercible) *Node {
8901-
return cloneNode(f.AsNodeFactory().NewJSDocLinkPlain(node.Name(), node.Text), node.AsNode(), f.AsNodeFactory().hooks)
8901+
return cloneNode(f.AsNodeFactory().NewJSDocLinkPlain(node.Name(), node.text), node.AsNode(), f.AsNodeFactory().hooks)
89028902
}
89038903

89048904
func (node *JSDocLinkPlain) Name() *DeclarationName {
@@ -8910,16 +8910,16 @@ type JSDocLinkCode struct {
89108910
name *Node // optional (should only be EntityName)
89118911
}
89128912

8913-
func (f *NodeFactory) NewJSDocLinkCode(name *Node, text string) *Node {
8913+
func (f *NodeFactory) NewJSDocLinkCode(name *Node, text []string) *Node {
89148914
data := &JSDocLinkCode{}
89158915
data.name = name
8916-
data.Text = text
8916+
data.text = text
89178917
f.textCount++
89188918
return f.newNode(KindJSDocLinkCode, data)
89198919
}
89208920

8921-
func (f *NodeFactory) UpdateJSDocLinkCode(node *JSDocLinkCode, name *Node, text string) *Node {
8922-
if name != node.name || text != node.Text {
8921+
func (f *NodeFactory) UpdateJSDocLinkCode(node *JSDocLinkCode, name *Node, text []string) *Node {
8922+
if name != node.name || !core.Same(text, node.text) {
89238923
return updateNode(f.NewJSDocLinkCode(name, text), node.AsNode(), f.hooks)
89248924
}
89258925
return node.AsNode()
@@ -8930,11 +8930,11 @@ func (node *JSDocLinkCode) ForEachChild(v Visitor) bool {
89308930
}
89318931

89328932
func (node *JSDocLinkCode) VisitEachChild(v *NodeVisitor) *Node {
8933-
return v.Factory.UpdateJSDocLinkCode(node, v.visitNode(node.name), node.Text)
8933+
return v.Factory.UpdateJSDocLinkCode(node, v.visitNode(node.name), node.text)
89348934
}
89358935

89368936
func (node *JSDocLinkCode) Clone(f NodeFactoryCoercible) *Node {
8937-
return cloneNode(f.AsNodeFactory().NewJSDocLinkCode(node.Name(), node.Text), node.AsNode(), f.AsNodeFactory().hooks)
8937+
return cloneNode(f.AsNodeFactory().NewJSDocLinkCode(node.Name(), node.text), node.AsNode(), f.AsNodeFactory().hooks)
89388938
}
89398939

89408940
func (node *JSDocLinkCode) Name() *DeclarationName {

internal/core/pool.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ func (p *Pool[T]) NewSlice1(t T) []T {
4949
return slice
5050
}
5151

52+
func (p *Pool[T]) Clone(t []T) []T {
53+
if len(t) == 0 {
54+
return nil
55+
}
56+
slice := p.NewSlice(len(t))
57+
copy(slice, t)
58+
return slice
59+
}
60+
5261
func nextPoolSize(size int) int {
5362
// This compiles down branch-free.
5463
size = max(size, 1)

internal/ls/hover.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,10 +395,10 @@ func writeComments(b *strings.Builder, comments []*ast.Node) {
395395
for _, comment := range comments {
396396
switch comment.Kind {
397397
case ast.KindJSDocText:
398-
b.WriteString(comment.AsJSDocText().Text)
398+
b.WriteString(comment.Text())
399399
case ast.KindJSDocLink:
400400
name := comment.Name()
401-
text := comment.AsJSDocLink().Text
401+
text := comment.AsJSDocLink().Text()
402402
if name != nil {
403403
if text == "" {
404404
writeEntityName(b, name)

internal/parser/jsdoc.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ loop:
256256
if linkEnd == start {
257257
comments = removeLeadingNewlines(comments)
258258
}
259-
jsdocText := p.factory.NewJSDocText(strings.Join(comments, ""))
259+
jsdocText := p.factory.NewJSDocText(p.stringSlicePool.Clone(comments))
260260
p.finishNodeWithEnd(jsdocText, linkEnd, commentEnd)
261261
commentParts = append(commentParts, jsdocText, link)
262262
comments = comments[:0]
@@ -283,9 +283,8 @@ loop:
283283
commentsPos = p.scanner.TokenFullStart()
284284
}
285285

286-
trimmedComments := trimEnd(strings.Join(comments, ""))
287-
if len(trimmedComments) > 0 {
288-
jsdocText := p.factory.NewJSDocText(trimmedComments)
286+
if len(comments) > 0 {
287+
jsdocText := p.factory.NewJSDocText(p.stringSlicePool.Clone(comments))
289288
p.finishNodeWithEnd(jsdocText, linkEnd, commentsPos)
290289
commentParts = append(commentParts, jsdocText)
291290
}
@@ -529,7 +528,7 @@ loop:
529528
linkStart := p.scanner.TokenEnd() - 1
530529
link := p.parseJSDocLink(linkStart)
531530
if link != nil {
532-
text := p.factory.NewJSDocText(strings.Join(comments, ""))
531+
text := p.factory.NewJSDocText(p.stringSlicePool.Clone(comments))
533532
var commentStart int
534533
if linkEnd > -1 {
535534
commentStart = linkEnd
@@ -583,15 +582,14 @@ loop:
583582
p.jsdocTagCommentsSpace = comments[:0]
584583

585584
comments = removeLeadingNewlines(comments)
586-
trimmedComments := trimEnd(strings.Join(comments, ""))
587-
if len(trimmedComments) > 0 {
585+
if len(comments) > 0 {
588586
var commentStart int
589587
if linkEnd > -1 {
590588
commentStart = linkEnd
591589
} else {
592590
commentStart = commentsPos
593591
}
594-
text := p.factory.NewJSDocText(trimmedComments)
592+
text := p.factory.NewJSDocText(p.stringSlicePool.Clone(comments))
595593
p.finishNode(text, commentStart)
596594
parts = append(parts, text)
597595
}
@@ -620,11 +618,11 @@ func (p *Parser) parseJSDocLink(start int) *ast.Node {
620618
var create *ast.Node
621619
switch linkType {
622620
case "link":
623-
create = p.factory.NewJSDocLink(name, strings.Join(text, ""))
621+
create = p.factory.NewJSDocLink(name, text)
624622
case "linkcode":
625-
create = p.factory.NewJSDocLinkCode(name, strings.Join(text, ""))
623+
create = p.factory.NewJSDocLinkCode(name, text)
626624
default:
627-
create = p.factory.NewJSDocLinkPlain(name, strings.Join(text, ""))
625+
create = p.factory.NewJSDocLinkPlain(name, text)
628626
}
629627
p.finishNodeWithEnd(create, start, p.scanner.TokenEnd())
630628
return create

internal/parser/parser.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ type Parser struct {
7070
identifierCount int
7171
notParenthesizedArrow collections.Set[int]
7272
nodeSlicePool core.Pool[*ast.Node]
73+
stringSlicePool core.Pool[string]
7374
jsdocCache map[*ast.Node][]*ast.Node
7475
possibleAwaitSpans []int
7576
jsdocCommentsSpace []string

0 commit comments

Comments
 (0)