Skip to content

Commit 4b26ea0

Browse files
jensjohaCommit Bot
authored and
Commit Bot
committed
[CFE] Fix incremental_compiler_leak_test(er)
In https://dart-review.googlesource.com/c/sdk/+/214020 incremental_compiler_leak_test was renamed to incremental_compiler_leak_tester temporarily because it started saying we had possible leaks. Looking into it now, a number of puzzeling this were found: * Many SourceLibraryBuilders, SourceClassBuilders etc was alive despite having been converted to DillLibraryBuilders (etc). They shoudn't be. * Several Librarys (from kernels AST) came and went between invalidations. This all was caused by the VM sometimes keeping things around longer than it should (probably a variation of #36983). This CL fixes it by explicitley nulling things out (and similar). It re-enasbles the test and updates it to explicitley expecting a certain number of instances for some classes (e.g. it now expect 0 SourceLibraryBuilders). To be clear I don't think this has caused any "real" leaks, but: * having things clear up too late is very confusing. * we will probably use less memory now. Change-Id: I3a439f23fc7ef26b156c6164a2c37f6352bc57b4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/229964 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Jens Johansen <[email protected]>
1 parent 13713c2 commit 4b26ea0

File tree

3 files changed

+78
-21
lines changed

3 files changed

+78
-21
lines changed

pkg/front_end/lib/src/fasta/kernel/kernel_target.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ class KernelTarget extends TargetImplementation {
409409
if (macroApplications != null) {
410410
await macroApplications.applyTypeMacros();
411411
}
412-
List<SourceClassBuilder> sourceClassBuilders =
412+
List<SourceClassBuilder>? sourceClassBuilders =
413413
loader.checkSemantics(objectClassBuilder);
414414
loader.finishTypeVariables(objectClassBuilder, dynamicType);
415415
loader.createTypeInferenceEngine();
@@ -442,6 +442,11 @@ class KernelTarget extends TargetImplementation {
442442
loader.checkMainMethods();
443443
installAllComponentProblems(loader.allComponentProblems);
444444
loader.allComponentProblems.clear();
445+
// For whatever reason sourceClassBuilders is kept alive for some amount
446+
// of time, meaning that all source library builders will be kept alive
447+
// (for whatever amount of time) even though we convert them to dill
448+
// library builders. To avoid it we null it out here.
449+
sourceClassBuilders = null;
445450
return new BuildResult(
446451
component: component, macroApplications: macroApplications);
447452
}, () => loader.currentUriForCrashReporting);
@@ -467,7 +472,7 @@ class KernelTarget extends TargetImplementation {
467472
finishSynthesizedParameters();
468473
loader.finishDeferredLoadTearoffs();
469474
loader.finishNoSuchMethodForwarders();
470-
List<SourceClassBuilder> sourceClasses = loader.collectSourceClasses();
475+
List<SourceClassBuilder>? sourceClasses = loader.collectSourceClasses();
471476
if (macroApplications != null) {
472477
await macroApplications.applyDefinitionMacros(
473478
loader.coreTypes, loader.hierarchy);
@@ -479,6 +484,12 @@ class KernelTarget extends TargetImplementation {
479484

480485
if (verify) this.verify();
481486
installAllComponentProblems(loader.allComponentProblems);
487+
488+
// For whatever reason sourceClasses is kept alive for some amount
489+
// of time, meaning that all source library builders will be kept alive
490+
// (for whatever amount of time) even though we convert them to dill
491+
// library builders. To avoid it we null it out here.
492+
sourceClasses = null;
482493
return new BuildResult(
483494
component: component, macroApplications: macroApplications);
484495
}, () => loader.currentUriForCrashReporting);

pkg/front_end/lib/src/fasta/source/source_loader.dart

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,9 @@ class SourceLoader extends Loader {
642642
currentUriForCrashReporting = library.importUri;
643643
await buildBody(library);
644644
}
645+
// Workaround: This will return right away but avoid a "semi leak"
646+
// where the latest library is saved in a context somewhere.
647+
await buildBody(null);
645648
currentUriForCrashReporting = null;
646649
logSummary(templateSourceBodySummary);
647650
}
@@ -1076,7 +1079,10 @@ severity: $severity
10761079
}
10771080

10781081
/// Builds all the method bodies found in the given [library].
1079-
Future<Null> buildBody(SourceLibraryBuilder library) async {
1082+
Future<Null> buildBody(SourceLibraryBuilder? library) async {
1083+
// [library] is only nullable so we can call this a "dummy-time" to get rid
1084+
// of a semi-leak.
1085+
if (library == null) return;
10801086
Iterable<SourceLibraryBuilder>? patches = library.patchLibraries;
10811087
if (patches != null) {
10821088
for (SourceLibraryBuilder patchLibrary in patches) {

pkg/front_end/test/incremental_compiler_leak_tester.dart renamed to pkg/front_end/test/incremental_compiler_leak_test.dart

Lines changed: 58 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -85,30 +85,48 @@ class LeakFinder extends vmService.LaunchingVMServiceHelper {
8585
// For now ignore anything not in package:kernel or package:front_end.
8686
if (ignoredClass(classDetails)) continue;
8787

88+
bool isStrictClass = strictClass(classDetails);
89+
90+
int expectedStrictClassNumber = -1;
91+
if (isStrictClass) {
92+
expectedStrictClassNumber = strictClassExpectedNumber(classDetails);
93+
}
94+
8895
// If they're all equal there's nothing to talk about.
89-
bool same = true;
90-
for (int i = 1; i < listOfInstanceCounts.length; i++) {
96+
bool sameAndAsExpected = true;
97+
for (int i = 0; i < listOfInstanceCounts.length; i++) {
98+
if (expectedStrictClassNumber > -1 &&
99+
expectedStrictClassNumber != listOfInstanceCounts[i]) {
100+
sameAndAsExpected = false;
101+
break;
102+
}
91103
if (listOfInstanceCounts[i] != listOfInstanceCounts[0]) {
92-
same = false;
104+
sameAndAsExpected = false;
93105
break;
94106
}
95107
}
96-
if (same) continue;
108+
if (sameAndAsExpected) continue;
97109

98110
int midPoint = listOfInstanceCounts.length ~/ 2;
99111
List<int> firstHalf = listOfInstanceCounts.sublist(0, midPoint);
100112
List<int> secondHalf = listOfInstanceCounts.sublist(midPoint);
101113
TTestResult ttestResult = SimpleTTestStat.ttest(secondHalf, firstHalf);
102114

103-
if (!strictClass(classDetails)) {
115+
if (!isStrictClass) {
104116
if (!ttestResult.significant) continue;
105117

106118
// TODO(jensj): We could possibly also ignore if it's less (i.e. a
107119
// negative change), or if the change is < 1%, or the change minus the
108120
// confidence is < 1% etc.
109121
}
110-
print("Differences on ${c.name} (${uriString}): "
111-
"$listOfInstanceCounts ($ttestResult)");
122+
if (expectedStrictClassNumber > -1) {
123+
print("Differences on ${c.name} (${uriString}): "
124+
"Expected exactly $expectedStrictClassNumber but found "
125+
"$listOfInstanceCounts ($ttestResult)");
126+
} else {
127+
print("Differences on ${c.name} (${uriString}): "
128+
"$listOfInstanceCounts ($ttestResult)");
129+
}
112130
foundLeak = true;
113131
}
114132

@@ -219,20 +237,26 @@ class LeakFinder extends vmService.LaunchingVMServiceHelper {
219237
return true;
220238
}
221239

222-
// I have commented out the lazy ones below.
223-
Set<String> frontEndStrictClasses = {
240+
Map<String, int> frontEndStrictClasses = {
241+
// The inner working of dills are created lazily:
224242
// "DillClassBuilder",
225243
// "DillExtensionBuilder",
226244
// "DillExtensionMemberBuilder",
227-
"DillLibraryBuilder",
228-
"DillLoader",
229245
// "DillMemberBuilder",
230-
"DillTarget",
231246
// "DillTypeAliasBuilder",
232-
"SourceClassBuilder",
233-
"SourceExtensionBuilder",
234-
"SourceLibraryBuilder",
235-
"SourceLoader",
247+
248+
"DillLibraryBuilder": -1 /* unknown amount */,
249+
"DillLoader": 1,
250+
"DillTarget": 1,
251+
252+
// We convert all source builders to dill builders so we expect none to
253+
// exist after that.
254+
"SourceClassBuilder": 0,
255+
"SourceExtensionBuilder": 0,
256+
"SourceLibraryBuilder": 0,
257+
258+
// We still expect exactly 1 source loader though.
259+
"SourceLoader": 1,
236260
};
237261

238262
Set<String> kernelAstStrictClasses = {
@@ -248,18 +272,34 @@ class LeakFinder extends vmService.LaunchingVMServiceHelper {
248272

249273
bool strictClass(vmService.Class classDetails) {
250274
if (!kernelAstStrictClasses.contains(classDetails.name) &&
251-
!frontEndStrictClasses.contains(classDetails.name)) return false;
275+
!frontEndStrictClasses.containsKey(classDetails.name)) return false;
252276

253277
if (kernelAstStrictClasses.contains(classDetails.name) &&
254278
classDetails.location?.script?.uri == "package:kernel/ast.dart") {
255279
return true;
256280
}
257-
if (frontEndStrictClasses.contains(classDetails.name) &&
281+
if (frontEndStrictClasses.containsKey(classDetails.name) &&
258282
classDetails.location?.script?.uri?.startsWith("package:front_end/") ==
259283
true) {
260284
return true;
261285
}
262286

263287
throw "$classDetails: ${classDetails.name} --- ${classDetails.location}";
264288
}
289+
290+
int strictClassExpectedNumber(vmService.Class classDetails) {
291+
if (!strictClass(classDetails)) return -1;
292+
if (kernelAstStrictClasses.contains(classDetails.name) &&
293+
classDetails.location?.script?.uri == "package:kernel/ast.dart") {
294+
return -1;
295+
}
296+
int? result = frontEndStrictClasses[classDetails.name];
297+
if (result != null &&
298+
classDetails.location?.script?.uri?.startsWith("package:front_end/") ==
299+
true) {
300+
return result;
301+
}
302+
303+
throw "$classDetails: ${classDetails.name} --- ${classDetails.location}";
304+
}
265305
}

0 commit comments

Comments
 (0)