Skip to content

Commit 3566f69

Browse files
adonovangopherbot
authored andcommitted
gopls/internal/lsp/source: minor space optimizations
Memory profiles show heavy allocation for the stack and the function closure of FindDeclAndField. This change moves both outside the loop, reducing this function's fraction of allocation from 6.7% before to 5.0% after, and reducing running time by 3-7% on these benchmarks. before BenchmarkStructCompletion/completion-8 100 10432280 ns/op BenchmarkImportCompletion/completion-8 1350 921785 ns/op BenchmarkSliceCompletion/completion-8 100 10876852 ns/op BenchmarkFuncDeepCompletion/completion-8 142 7136768 ns/op BenchmarkCompletionFollowingEdit/completion-8 63 21267031 ns/op After BenchmarkStructCompletion/completion-8 100 10030458 ns/op BenchmarkImportCompletion/completion-8 1311 918306 ns/op BenchmarkSliceCompletion/completion-8 100 10179937 ns/op BenchmarkFuncDeepCompletion/completion-8 150 6986303 ns/op BenchmarkCompletionFollowingEdit/completion-8 63 20575987 ns/op Change-Id: Ia459e41ecf20851ff4544f76ad7b415a24606cd1 Reviewed-on: https://go-review.googlesource.com/c/tools/+/446185 TryBot-Result: Gopher Robot <[email protected]> gopls-CI: kokoro <[email protected]> Run-TryBot: Alan Donovan <[email protected]> Auto-Submit: Alan Donovan <[email protected]> Reviewed-by: Robert Findley <[email protected]>
1 parent 7cdb0e7 commit 3566f69

File tree

1 file changed

+58
-56
lines changed

1 file changed

+58
-56
lines changed

gopls/internal/lsp/source/hover.go

Lines changed: 58 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -904,78 +904,80 @@ func FindDeclAndField(files []*ast.File, pos token.Pos) (decl ast.Decl, field *a
904904
}()
905905

906906
// Visit the files in search of the node at pos.
907-
var stack []ast.Node
908-
for _, file := range files {
909-
ast.Inspect(file, func(n ast.Node) bool {
910-
if n != nil {
911-
stack = append(stack, n) // push
912-
} else {
913-
stack = stack[:len(stack)-1] // pop
914-
return false
915-
}
907+
stack := make([]ast.Node, 0, 20)
908+
// Allocate the closure once, outside the loop.
909+
f := func(n ast.Node) bool {
910+
if n != nil {
911+
stack = append(stack, n) // push
912+
} else {
913+
stack = stack[:len(stack)-1] // pop
914+
return false
915+
}
916916

917-
// Skip subtrees (incl. files) that don't contain the search point.
918-
if !(n.Pos() <= pos && pos < n.End()) {
919-
return false
920-
}
917+
// Skip subtrees (incl. files) that don't contain the search point.
918+
if !(n.Pos() <= pos && pos < n.End()) {
919+
return false
920+
}
921921

922-
switch n := n.(type) {
923-
case *ast.Field:
924-
checkField := func(f ast.Node) {
925-
if f.Pos() == pos {
926-
field = n
927-
for i := len(stack) - 1; i >= 0; i-- {
928-
if d, ok := stack[i].(ast.Decl); ok {
929-
decl = d // innermost enclosing decl
930-
break
931-
}
922+
switch n := n.(type) {
923+
case *ast.Field:
924+
checkField := func(f ast.Node) {
925+
if f.Pos() == pos {
926+
field = n
927+
for i := len(stack) - 1; i >= 0; i-- {
928+
if d, ok := stack[i].(ast.Decl); ok {
929+
decl = d // innermost enclosing decl
930+
break
932931
}
933-
panic(nil) // found
934932
}
933+
panic(nil) // found
935934
}
935+
}
936936

937-
// Check *ast.Field itself. This handles embedded
938-
// fields which have no associated *ast.Ident name.
939-
checkField(n)
937+
// Check *ast.Field itself. This handles embedded
938+
// fields which have no associated *ast.Ident name.
939+
checkField(n)
940940

941-
// Check each field name since you can have
942-
// multiple names for the same type expression.
943-
for _, name := range n.Names {
944-
checkField(name)
945-
}
941+
// Check each field name since you can have
942+
// multiple names for the same type expression.
943+
for _, name := range n.Names {
944+
checkField(name)
945+
}
946946

947-
// Also check "X" in "...X". This makes it easy
948-
// to format variadic signature params properly.
949-
if ell, ok := n.Type.(*ast.Ellipsis); ok && ell.Elt != nil {
950-
checkField(ell.Elt)
951-
}
947+
// Also check "X" in "...X". This makes it easy
948+
// to format variadic signature params properly.
949+
if ell, ok := n.Type.(*ast.Ellipsis); ok && ell.Elt != nil {
950+
checkField(ell.Elt)
951+
}
952952

953-
case *ast.FuncDecl:
954-
if n.Name.Pos() == pos {
955-
decl = n
956-
panic(nil) // found
957-
}
953+
case *ast.FuncDecl:
954+
if n.Name.Pos() == pos {
955+
decl = n
956+
panic(nil) // found
957+
}
958958

959-
case *ast.GenDecl:
960-
for _, spec := range n.Specs {
961-
switch spec := spec.(type) {
962-
case *ast.TypeSpec:
963-
if spec.Name.Pos() == pos {
959+
case *ast.GenDecl:
960+
for _, spec := range n.Specs {
961+
switch spec := spec.(type) {
962+
case *ast.TypeSpec:
963+
if spec.Name.Pos() == pos {
964+
decl = n
965+
panic(nil) // found
966+
}
967+
case *ast.ValueSpec:
968+
for _, id := range spec.Names {
969+
if id.Pos() == pos {
964970
decl = n
965971
panic(nil) // found
966972
}
967-
case *ast.ValueSpec:
968-
for _, id := range spec.Names {
969-
if id.Pos() == pos {
970-
decl = n
971-
panic(nil) // found
972-
}
973-
}
974973
}
975974
}
976975
}
977-
return true
978-
})
976+
}
977+
return true
978+
}
979+
for _, file := range files {
980+
ast.Inspect(file, f)
979981
}
980982

981983
return nil, nil

0 commit comments

Comments
 (0)