Skip to content

Commit cab6754

Browse files
committed
wild idea
1 parent 2aa47f2 commit cab6754

File tree

3 files changed

+52
-3
lines changed

3 files changed

+52
-3
lines changed

internal/compiler/fileloader.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,10 @@ func processAllProgramFiles(
138138
CurrentDirectory: opts.Host.GetCurrentDirectory(),
139139
},
140140
filesParser: &filesParser{
141-
wg: core.NewThrottledWorkGroup(singleThreaded),
142-
maxDepth: maxNodeModuleJsDepth,
141+
wg: core.NewWorkGroup(singleThreaded),
142+
resolveSem: core.NewSemaphore(singleThreaded),
143+
parseSem: core.NewSemaphore(singleThreaded),
144+
maxDepth: maxNodeModuleJsDepth,
143145
},
144146
rootTasks: make([]*parseTask, 0, len(rootFiles)+len(compilerOptions.Lib)),
145147
supportedExtensions: supportedExtensions,
@@ -268,7 +270,7 @@ func (p *fileLoader) addProjectReferenceTasks(singleThreaded bool) {
268270

269271
parser := &projectReferenceParser{
270272
loader: p,
271-
wg: core.NewThrottledWorkGroup(singleThreaded),
273+
wg: core.NewWorkGroup(singleThreaded),
272274
}
273275
rootTasks := createProjectReferenceParseTasks(projectReferences)
274276
parser.parse(rootTasks)

internal/compiler/filesparser.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,17 +102,26 @@ func (t *parseTask) load(loader *fileLoader) {
102102
// to avoid adding spurious lookups to file watcher tracking.
103103
t.metadata = ast.SourceFileMetaData{ImpliedNodeFormat: core.ResolutionModeCommonJS}
104104
} else {
105+
// Resolution: load metadata (package.json lookups involve stat calls).
106+
loader.filesParser.resolveSem.Acquire()
105107
t.metadata = loader.loadSourceFileMetaData(t.normalizedFilePath)
108+
loader.filesParser.resolveSem.Release()
106109
}
107110

111+
// Parsing: parse the source file (CPU-heavy).
112+
loader.filesParser.parseSem.Acquire()
108113
file := loader.parseSourceFile(t)
114+
loader.filesParser.parseSem.Release()
109115
if file == nil {
110116
return
111117
}
112118

113119
t.file = file
114120
t.subTasks = make([]*parseTask, 0, len(file.ReferencedFiles)+len(file.Imports())+len(file.ModuleAugmentations))
115121

122+
// Resolution: resolve references, type directives, and imports (stat-heavy).
123+
loader.filesParser.resolveSem.Acquire()
124+
116125
compilerOptions := loader.opts.Config.CompilerOptions()
117126
if !compilerOptions.NoResolve.IsTrue() {
118127
for index, ref := range file.ReferencedFiles {
@@ -152,6 +161,8 @@ func (t *parseTask) load(loader *fileLoader) {
152161
}
153162

154163
loader.resolveImportsAndModuleAugmentations(t)
164+
165+
loader.filesParser.resolveSem.Release()
155166
}
156167

157168
func (t *parseTask) redirect(loader *fileLoader, fileName string) {
@@ -165,6 +176,8 @@ func (t *parseTask) redirect(loader *fileLoader, fileName string) {
165176
}
166177

167178
func (t *parseTask) loadAutomaticTypeDirectives(loader *fileLoader) {
179+
loader.filesParser.resolveSem.Acquire()
180+
defer loader.filesParser.resolveSem.Release()
168181
toParseTypeRefs, typeResolutionsInFile, typeResolutionsTrace, pDiagnostics := loader.resolveAutomaticTypeDirectives(t.normalizedFilePath)
169182
t.typeResolutionsInFile = typeResolutionsInFile
170183
t.typeResolutionsTrace = typeResolutionsTrace
@@ -197,6 +210,8 @@ func (t *parseTask) addSubTask(ref resolvedRef, libFile *LibFile) {
197210

198211
type filesParser struct {
199212
wg core.WorkGroup
213+
resolveSem *core.Semaphore
214+
parseSem *core.Semaphore
200215
taskDataByPath collections.SyncMap[tspath.Path, *parseTaskData]
201216
maxDepth int
202217
}

internal/core/workgroup.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,38 @@ func NewThrottledWorkGroup(singleThreaded bool) WorkGroup {
3636
}
3737
}
3838

39+
// Semaphore limits concurrent access to a resource.
40+
// A nil *Semaphore is valid and performs no limiting;
41+
// callers are expected to arrange sequential execution themselves
42+
// when no semaphore is provided.
43+
type Semaphore struct {
44+
ch chan struct{}
45+
}
46+
47+
// NewSemaphore creates a Semaphore sized to GOMAXPROCS.
48+
// Returns nil when singleThreaded is true, as the caller's WorkGroup
49+
// already ensures sequential execution.
50+
func NewSemaphore(singleThreaded bool) *Semaphore {
51+
if singleThreaded {
52+
return nil
53+
}
54+
return &Semaphore{ch: make(chan struct{}, runtime.GOMAXPROCS(0))}
55+
}
56+
57+
// Acquire blocks until a slot is available.
58+
func (s *Semaphore) Acquire() {
59+
if s != nil {
60+
s.ch <- struct{}{}
61+
}
62+
}
63+
64+
// Release frees a slot.
65+
func (s *Semaphore) Release() {
66+
if s != nil {
67+
<-s.ch
68+
}
69+
}
70+
3971
type parallelWorkGroup struct {
4072
done atomic.Bool
4173
wg sync.WaitGroup

0 commit comments

Comments
 (0)