@@ -71,7 +71,53 @@ abstract class IncrementalCompilerRunner<
7171        providedChangedFiles :  ChangedFiles ? ,
7272        projectDir :  File ?  = null
7373    ): ExitCode  =  reporter.measure(BuildTime .INCREMENTAL_COMPILATION_DAEMON ) {
74-         compileImpl(allSourceFiles, args, messageCollector, providedChangedFiles, projectDir)
74+         try  {
75+             compileImpl(allSourceFiles, args, messageCollector, providedChangedFiles, projectDir)
76+         } finally  {
77+             reporter.measure(BuildTime .CALCULATE_OUTPUT_SIZE ) {
78+                 reporter.addMetric(
79+                     BuildPerformanceMetric .SNAPSHOT_SIZE ,
80+                     buildHistoryFile.length() +  lastBuildInfoFile.length() +  abiSnapshotFile.length()
81+                 )
82+                 if  (cacheDirectory.exists() &&  cacheDirectory.isDirectory()) {
83+                     cacheDirectory.walkTopDown().filter { it.isFile }.map { it.length() }.sum().let  {
84+                         reporter.addMetric(BuildPerformanceMetric .CACHE_DIRECTORY_SIZE , it)
85+                     }
86+                 }
87+             }
88+         }
89+     }
90+ 
91+     fun  rebuild (
92+         reason :  BuildAttribute ,
93+         allSourceFiles :  List <File >,
94+         args :  Args ,
95+         messageCollector :  MessageCollector ,
96+         providedChangedFiles :  ChangedFiles ? ,
97+         projectDir :  File ?  = null,
98+         classpathAbiSnapshot :  Map <String , AbiSnapshot >
99+     ): ExitCode  {
100+         reporter.report { " Non-incremental compilation will be performed: $reason " 
101+         reporter.measure(BuildTime .CLEAR_OUTPUT_ON_REBUILD ) {
102+             cleanOutputsAndLocalStateOnRebuild(args)
103+         }
104+         val  caches =  createCacheManager(args, projectDir)
105+         try  {
106+             if  (providedChangedFiles ==  null ) {
107+                 caches.inputsCache.sourceSnapshotMap.compareAndUpdate(allSourceFiles)
108+             }
109+             val  allKotlinFiles =  allSourceFiles.filter { it.isKotlinFile(kotlinSourceFilesExtensions) }
110+             return  compileIncrementally(
111+                 args, caches, allKotlinFiles, CompilationMode .Rebuild (reason), messageCollector, withAbiSnapshot,
112+                 classpathAbiSnapshot =  classpathAbiSnapshot
113+             ).also  {
114+                 if  (it ==  ExitCode .OK ) {
115+                     performWorkAfterSuccessfulCompilation(caches)
116+                 }
117+             }
118+         } finally  {
119+             caches.close(true )
120+         }
75121    }
76122
77123    private  fun  compileImpl (
@@ -82,41 +128,19 @@ abstract class IncrementalCompilerRunner<
82128        projectDir :  File ?  = null
83129    ): ExitCode  {
84130        var  caches =  createCacheManager(args, projectDir)
131+         var  rebuildReason =  BuildAttribute .INTERNAL_ERROR 
85132
86-         if  (withAbiSnapshot) {
87-             reporter.report { " Incremental compilation with ABI snapshot enabled" 
88-         }
89-         // TODO if abi-snapshot is corrupted unable to rebuild. Should roll back to withSnapshot = false?
90133        val  classpathAbiSnapshot = 
91134            if  (withAbiSnapshot) {
135+                 reporter.report { " Incremental compilation with ABI snapshot enabled" 
92136                reporter.measure(BuildTime .SET_UP_ABI_SNAPSHOTS ) {
93137                    setupJarDependencies(args, withAbiSnapshot, reporter)
94138                }
95139            } else  {
96140                emptyMap()
97141            }
98142
99-         fun  rebuild (reason :  BuildAttribute ): ExitCode  {
100-             reporter.report { " Non-incremental compilation will be performed: $reason " 
101-             caches.close(false )
102-             //  todo: we can recompile all files incrementally (not cleaning caches), so rebuild won't propagate
103-             reporter.measure(BuildTime .CLEAR_OUTPUT_ON_REBUILD ) {
104-                 cleanOutputsAndLocalStateOnRebuild(args)
105-             }
106-             caches =  createCacheManager(args, projectDir)
107-             if  (providedChangedFiles ==  null ) {
108-                 caches.inputsCache.sourceSnapshotMap.compareAndUpdate(allSourceFiles)
109-             }
110-             val  allKotlinFiles =  allSourceFiles.filter { it.isKotlinFile(kotlinSourceFilesExtensions) }
111-             return  compileIncrementally(
112-                 args, caches, allKotlinFiles, CompilationMode .Rebuild (reason), messageCollector, withAbiSnapshot,
113-                 classpathAbiSnapshot =  classpathAbiSnapshot
114-             )
115-         }
116- 
117-         //  If compilation has crashed or we failed to close caches we have to clear them
118-         var  cachesMayBeCorrupted =  true 
119-         return  try  {
143+         try  {
120144            val  changedFiles =  when  (providedChangedFiles) {
121145                is  ChangedFiles .Dependencies  ->  {
122146                    val  changedSources =  caches.inputsCache.sourceSnapshotMap.compareAndUpdate(allSourceFiles)
@@ -129,75 +153,51 @@ abstract class IncrementalCompilerRunner<
129153                else  ->  providedChangedFiles
130154            }
131155
132-             @Suppress(" MoveVariableDeclarationIntoWhen" 
133-             val  compilationMode =  sourcesToCompile(caches, changedFiles, args, messageCollector, classpathAbiSnapshot)
156+             var  compilationMode =  sourcesToCompile(caches, changedFiles, args, messageCollector, classpathAbiSnapshot)
157+             val  abiSnapshot =  if  (compilationMode is  CompilationMode .Incremental  &&  withAbiSnapshot) {
158+                 AbiSnapshotImpl .read(abiSnapshotFile, reporter)
159+             } else  {
160+                 if  (withAbiSnapshot) {
161+                     compilationMode =  CompilationMode .Rebuild (BuildAttribute .NO_ABI_SNAPSHOT )
162+                 }
163+                 null 
164+             }
134165
135-             val  exitCode  =   when  (compilationMode) {
166+             when  (compilationMode) {
136167                is  CompilationMode .Incremental  ->  {
137-                     if  (withAbiSnapshot) {
138-                         val  abiSnapshot =  AbiSnapshotImpl .read(abiSnapshotFile, reporter)
139-                         if  (abiSnapshot !=  null ) {
168+                     try  {
169+                         val  exitCode =  if  (withAbiSnapshot) {
140170                            compileIncrementally(
141-                                 args,
142-                                 caches,
143-                                 allSourceFiles,
144-                                 compilationMode,
145-                                 messageCollector,
146-                                 withAbiSnapshot,
147-                                 abiSnapshot,
148-                                 classpathAbiSnapshot
171+                                 args, caches, allSourceFiles, compilationMode, messageCollector,
172+                                 withAbiSnapshot, abiSnapshot!! , classpathAbiSnapshot
149173                            )
150174                        } else  {
151-                             rebuild( BuildAttribute . NO_ABI_SNAPSHOT )
175+                             compileIncrementally(args, caches, allSourceFiles, compilationMode, messageCollector, withAbiSnapshot )
152176                        }
153-                     } else  {
154-                         compileIncrementally(
155-                             args,
156-                             caches,
157-                             allSourceFiles,
158-                             compilationMode,
159-                             messageCollector,
160-                             withAbiSnapshot
161-                         )
162-                     }
163-                 }
164-                 is  CompilationMode .Rebuild  ->  {
165-                     rebuild(compilationMode.reason)
166-                 }
167-             }
168- 
169-             if  (exitCode ==  ExitCode .OK ) {
170-                 performWorkAfterSuccessfulCompilation(caches)
171-             }
172- 
173-             if  (! caches.close(flush =  true )) throw  RuntimeException (" Could not flush caches" 
174-             //  Here we should analyze exit code of compiler. E.g. compiler failure should lead to caches rebuild,
175-             //  but now JsKlib compiler reports invalid exit code.
176-             cachesMayBeCorrupted =  false 
177- 
178-             reporter.measure(BuildTime .CALCULATE_OUTPUT_SIZE ) {
179-                 reporter.addMetric(
180-                     BuildPerformanceMetric .SNAPSHOT_SIZE ,
181-                     buildHistoryFile.length() +  lastBuildInfoFile.length() +  abiSnapshotFile.length()
182-                 )
183-                 if  (cacheDirectory.exists() &&  cacheDirectory.isDirectory()) {
184-                     cacheDirectory.walkTopDown().filter { it.isFile }.map { it.length() }.sum().let  {
185-                         reporter.addMetric(BuildPerformanceMetric .CACHE_DIRECTORY_SIZE , it)
177+                         if  (exitCode ==  ExitCode .OK ) {
178+                             performWorkAfterSuccessfulCompilation(caches)
179+                         }
180+                         return  exitCode
181+                     } catch  (e:  Throwable ) {
182+                         reporter.report {
183+                             " Incremental compilation failed: ${e.stackTraceToString()} .\n Falling back to non-incremental compilation." 
184+                         }
185+                         rebuildReason =  BuildAttribute .INCREMENTAL_COMPILATION_FAILED 
186186                    }
187187                }
188+                 is  CompilationMode .Rebuild  ->  rebuildReason =  compilationMode.reason
188189            }
189-             return  exitCode
190-         } catch  (e:  Exception ) { //  todo: catch only cache corruption
191-             //  todo: warn?
192-             reporter.report { " Possible caches corruption: $e " 
193-             rebuild(BuildAttribute .CACHE_CORRUPTION ).also  {
194-                 cachesMayBeCorrupted =  false 
190+         } catch  (e:  Exception ) {
191+             reporter.report {
192+                 " Incremental compilation analysis failed: ${e.stackTraceToString()} .\n Falling back to non-incremental compilation." 
195193            }
196194        } finally  {
197-             if  (cachesMayBeCorrupted) {
195+             if  (! caches.close()) {
196+                 reporter.report { " Unable to close IC caches. Cleaning internal state" 
198197                cleanOutputsAndLocalStateOnRebuild(args)
199198            }
200199        }
200+         return  rebuild(rebuildReason, allSourceFiles, args, messageCollector, providedChangedFiles, projectDir, classpathAbiSnapshot)
201201    }
202202
203203    /* *
@@ -411,7 +411,10 @@ abstract class IncrementalCompilerRunner<
411411                break 
412412            }
413413
414-             val  (dirtyLookupSymbols, dirtyClassFqNames, forceRecompile) =  changesCollector.getDirtyData(listOf (caches.platformCache), reporter)
414+             val  (dirtyLookupSymbols, dirtyClassFqNames, forceRecompile) =  changesCollector.getDirtyData(
415+                 listOf (caches.platformCache),
416+                 reporter
417+             )
415418            val  compiledInThisIterationSet =  sourcesToCompile.toHashSet()
416419
417420            val  forceToRecompileFiles =  mapClassesFqNamesToFiles(listOf (caches.platformCache), forceRecompile, reporter)
0 commit comments