From 32ac1f159212365134142489e205c2a313c17c74 Mon Sep 17 00:00:00 2001 From: Marius Schulz Date: Sun, 7 Jun 2026 16:05:07 +0000 Subject: [PATCH] Inline GetCombinedNodeFlags/GetCombinedModifierFlags bodies MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the generic getCombinedFlags[T] helper with direct field reads in GetCombinedNodeFlags (node.Flags) and GetCombinedModifierFlags (node.ModifierFlags()). The parent-walk and OR-accumulation are unchanged; this just removes the indirect call through a function pointer at each step. getCombinedFlags and the trivial getNodeFlags wrapper had no other callers and are removed. Adds BenchmarkGetCombinedFlags over the standard fixture set. BenchmarkGetCombinedFlags (interleaved n=12, GOGC=off, benchtime=200x): | Fixture | Before | After | Δ | |---------------------------|---------------|--------------|---------| | checker.ts | 805.4 µs | 610.8 µs | −24.2% | | dom.generated.d.ts | 284.0 µs | 177.9 µs | −37.4% | | Herebyfile.mjs | 11.22 µs | 6.17 µs | −45.0% | | jsxComplexSignature….tsx | 2.73 µs | 1.53 µs | −43.8% | VS Code end-to-end (tsgo -p vscode/src --noEmit), single-threaded: | Metric | Before | After | Δ | |---------------------------------------|------------------|-----------------|-------------------------| | instructions:u (GOGC=off, min-of-3) | 100,168,751,028 | 99,897,715,729 | −0.27% | | wall, mean (interleaved n=14) | 20.92 s | 20.66 s | −1.24% (p=0.149, n.s.) | | Types / Symbols / Instantiations | identical | identical | | VS Code end-to-end, parallel (default GOMAXPROCS): | Metric | Before | After | Δ | |---------------------------------|---------|---------|-------------------------| | wall, mean (interleaved n=16) | 7.07 s | 7.12 s | +0.77% (p=0.652, n.s.) | --- internal/ast/utilities.go | 30 +++++++++-------- internal/ast/utilities_bench_test.go | 48 ++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 internal/ast/utilities_bench_test.go diff --git a/internal/ast/utilities.go b/internal/ast/utilities.go index 8554c14276a..f1220cea7f4 100644 --- a/internal/ast/utilities.go +++ b/internal/ast/utilities.go @@ -1143,32 +1143,36 @@ func GetRootDeclaration(node *Node) *Node { return node } -func getCombinedFlags[T ~uint32](node *Node, getFlags func(*Node) T) T { +func GetCombinedModifierFlags(node *Node) ModifierFlags { node = GetRootDeclaration(node) - flags := getFlags(node) + flags := node.ModifierFlags() if node.Kind == KindVariableDeclaration { node = node.Parent } if node != nil && node.Kind == KindVariableDeclarationList { - flags |= getFlags(node) + flags |= node.ModifierFlags() node = node.Parent } if node != nil && node.Kind == KindVariableStatement { - flags |= getFlags(node) + flags |= node.ModifierFlags() } return flags } -func GetCombinedModifierFlags(node *Node) ModifierFlags { - return getCombinedFlags(node, (*Node).ModifierFlags) -} - func GetCombinedNodeFlags(node *Node) NodeFlags { - return getCombinedFlags(node, getNodeFlags) -} - -func getNodeFlags(node *Node) NodeFlags { - return node.Flags + node = GetRootDeclaration(node) + flags := node.Flags + if node.Kind == KindVariableDeclaration { + node = node.Parent + } + if node != nil && node.Kind == KindVariableDeclarationList { + flags |= node.Flags + node = node.Parent + } + if node != nil && node.Kind == KindVariableStatement { + flags |= node.Flags + } + return flags } // Gets whether a bound `VariableDeclaration` or `VariableDeclarationList` is part of an `await using` declaration. diff --git a/internal/ast/utilities_bench_test.go b/internal/ast/utilities_bench_test.go new file mode 100644 index 00000000000..30e4465ba1b --- /dev/null +++ b/internal/ast/utilities_bench_test.go @@ -0,0 +1,48 @@ +package ast_test + +import ( + "testing" + + "github.com/microsoft/typescript-go/internal/ast" + "github.com/microsoft/typescript-go/internal/core" + "github.com/microsoft/typescript-go/internal/parser" + "github.com/microsoft/typescript-go/internal/testutil/fixtures" + "github.com/microsoft/typescript-go/internal/tspath" + "github.com/microsoft/typescript-go/internal/vfs/osvfs" +) + +func BenchmarkGetCombinedFlags(b *testing.B) { + for _, f := range fixtures.BenchFixtures { + b.Run(f.Name(), func(b *testing.B) { + f.SkipIfNotExist(b) + + fileName := tspath.GetNormalizedAbsolutePath(f.Path(), "/") + path := tspath.ToPath(fileName, "/", osvfs.FS().UseCaseSensitiveFileNames()) + sourceText := f.ReadFile(b) + scriptKind := core.GetScriptKindFromFileName(fileName) + + sourceFile := parser.ParseSourceFile(ast.SourceFileParseOptions{ + FileName: fileName, + Path: path, + }, sourceText, scriptKind) + + var decls []*ast.Node + var collect ast.Visitor + collect = func(n *ast.Node) bool { + if ast.IsDeclaration(n) { + decls = append(decls, n) + } + n.ForEachChild(collect) + return false + } + sourceFile.AsNode().ForEachChild(collect) + + for b.Loop() { + for _, n := range decls { + _ = ast.GetCombinedNodeFlags(n) + _ = ast.GetCombinedModifierFlags(n) + } + } + }) + } +}