Skip to content

Commit

Permalink
(dart2js) release some data-structures after resolution.
Browse files Browse the repository at this point in the history
The resolution-world-builder and impact transformer were holding onto a
class-hierarchy-builder in dart2js, which uses a lot of space.

On a some artificial sample apps with thousands of classes this
reduces the overall memory capacity by 25%. On a large internal app
this reduced the overall memory capacity from 13G to 11G.

Change-Id: I5d0d40764649364f2cd2411ef1346812beb411c4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/129544
Commit-Queue: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Stephen Adams <sra@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
  • Loading branch information
sigmundch authored and commit-bot@chromium.org committed Jan 3, 2020
1 parent b5bf014 commit 4eae396
Show file tree
Hide file tree
Showing 17 changed files with 53 additions and 73 deletions.
34 changes: 13 additions & 21 deletions pkg/compiler/lib/src/compiler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,10 @@ abstract class Compiler {
return new JsBackendStrategy(this);
}

ResolutionWorldBuilder get resolutionWorldBuilder =>
enqueuer.resolution.worldBuilder;
ResolutionWorldBuilder resolutionWorldBuilderForTesting;

KClosedWorld get frontendClosedWorldForTesting =>
resolutionWorldBuilderForTesting.closedWorldForTesting;

CodegenWorldBuilder get codegenWorldBuilder {
assert(
Expand Down Expand Up @@ -301,24 +303,12 @@ abstract class Compiler {
}
}

/// Starts the resolution phase, creating the [ResolutionEnqueuer] if not
/// already created.
///
/// During normal compilation resolution only started once, but through
/// [analyzeUri] resolution is started repeatedly.
ResolutionEnqueuer startResolution() {
ResolutionEnqueuer resolutionEnqueuer;
if (enqueuer.hasResolution) {
resolutionEnqueuer = enqueuer.resolution;
} else {
resolutionEnqueuer = enqueuer.createResolutionEnqueuer();
frontendStrategy.onResolutionStart();
}
return resolutionEnqueuer;
}

JClosedWorld computeClosedWorld(Uri rootLibraryUri, Iterable<Uri> libraries) {
ResolutionEnqueuer resolutionEnqueuer = startResolution();
ResolutionEnqueuer resolutionEnqueuer = enqueuer.createResolutionEnqueuer();
if (retainDataForTesting) {
resolutionWorldBuilderForTesting = resolutionEnqueuer.worldBuilder;
}
frontendStrategy.onResolutionStart();
for (LibraryEntity library
in frontendStrategy.elementEnvironment.libraries) {
frontendStrategy.elementEnvironment.forEachClass(library,
Expand Down Expand Up @@ -361,7 +351,8 @@ abstract class Compiler {
assert(mainFunction != null);
checkQueue(resolutionEnqueuer);

JClosedWorld closedWorld = closeResolution(mainFunction);
JClosedWorld closedWorld =
closeResolution(mainFunction, resolutionEnqueuer.worldBuilder);
if (retainDataForTesting) {
backendClosedWorldForTesting = closedWorld;
}
Expand Down Expand Up @@ -444,7 +435,8 @@ abstract class Compiler {
}

/// Perform the steps needed to fully end the resolution phase.
JClosedWorld closeResolution(FunctionEntity mainFunction) {
JClosedWorld closeResolution(FunctionEntity mainFunction,
ResolutionWorldBuilder resolutionWorldBuilder) {
phase = PHASE_DONE_RESOLVING;

KClosedWorld kClosedWorld = resolutionWorldBuilder.closeWorld(reporter);
Expand Down
4 changes: 2 additions & 2 deletions pkg/compiler/lib/src/deferred_load.dart
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ abstract class DeferredLoadTask extends CompilerTask {
MemberEntity element, Dependencies dependencies) {
// TODO(sigurdm): We want to be more specific about this - need a better
// way to query "liveness".
if (!compiler.resolutionWorldBuilder.isMemberUsed(element)) {
if (!closedWorld.isMemberUsed(element)) {
return;
}
_collectDependenciesFromImpact(closedWorld, element, dependencies);
Expand All @@ -203,7 +203,7 @@ abstract class DeferredLoadTask extends CompilerTask {
// to. Static members are not relevant, unless we are processing
// extra dependencies due to mirrors.
void addLiveInstanceMember(MemberEntity member) {
if (!compiler.resolutionWorldBuilder.isMemberUsed(member)) return;
if (!closedWorld.isMemberUsed(member)) return;
if (!member.isInstanceMember) return;
dependencies.addMember(member);
_collectDirectMemberDependencies(closedWorld, member, dependencies);
Expand Down
33 changes: 18 additions & 15 deletions pkg/compiler/lib/src/enqueue.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ import 'util/util.dart' show Setlet;
import 'world.dart' show JClosedWorld;

class EnqueueTask extends CompilerTask {
ResolutionEnqueuer _resolution;
ResolutionEnqueuer resolutionEnqueuerForTesting;
bool _resolutionEnqueuerCreated = false;
CodegenEnqueuer codegenEnqueuerForTesting;
final Compiler compiler;

Expand All @@ -48,22 +49,16 @@ class EnqueueTask extends CompilerTask {
: this.compiler = compiler,
super(compiler.measurer);

// TODO(johnniwinther): Remove the need for this.
bool get hasResolution => _resolution != null;

// TODO(johnniwinther): Remove the need for this.
ResolutionEnqueuer get resolution {
assert(
_resolution != null,
failedAt(NO_LOCATION_SPANNABLE,
"ResolutionEnqueuer has not been created yet."));
return _resolution;
}

ResolutionEnqueuer createResolutionEnqueuer() {
return _resolution ??= compiler.frontendStrategy
assert(!_resolutionEnqueuerCreated);
_resolutionEnqueuerCreated = true;
ResolutionEnqueuer enqueuer = compiler.frontendStrategy
.createResolutionEnqueuer(this, compiler)
..onEmptyForTesting = compiler.onResolutionQueueEmptyForTesting;
if (retainDataForTesting) {
resolutionEnqueuerForTesting = enqueuer;
}
return enqueuer;
}

Enqueuer createCodegenEnqueuer(
Expand Down Expand Up @@ -241,7 +236,7 @@ class ResolutionEnqueuer extends EnqueuerImpl {
final Set<ClassEntity> _recentClasses = new Setlet<ClassEntity>();
bool _recentConstants = false;
final ResolutionEnqueuerWorldBuilder _worldBuilder;
final WorkItemBuilder _workItemBuilder;
WorkItemBuilder _workItemBuilder;
final DiagnosticReporter _reporter;
final AnnotationsData _annotationsData;

Expand Down Expand Up @@ -492,6 +487,14 @@ class ResolutionEnqueuer extends EnqueuerImpl {
@override
bool get isResolutionQueue => true;

@override
void close() {
super.close();
// Null out _workItemBuilder to release memory (it internally holds large
// data-structures unnecessary after resolution.)
_workItemBuilder = null;
}

/// Registers [entity] as processed by the resolution enqueuer. Used only for
/// testing.
void registerProcessedElementInternal(MemberEntity entity) {
Expand Down
5 changes: 1 addition & 4 deletions pkg/compiler/lib/src/kernel/kernel_strategy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,6 @@ class KernelFrontendStrategy extends FrontendStrategy {

KFieldAnalysis _fieldAnalysis;

/// Backend transformation methods for the world impacts.
ImpactTransformer impactTransformer;

@override
NoSuchMethodRegistry noSuchMethodRegistry;

Expand Down Expand Up @@ -166,7 +163,7 @@ class KernelFrontendStrategy extends FrontendStrategy {
// before creating the resolution enqueuer.
AnnotationsData annotationsData = new AnnotationsDataImpl(
compiler.options, annotationsDataBuilder.pragmaAnnotations);
impactTransformer = new JavaScriptImpactTransformer(
ImpactTransformer impactTransformer = new JavaScriptImpactTransformer(
elementEnvironment,
commonElements,
impacts,
Expand Down
6 changes: 0 additions & 6 deletions pkg/compiler/lib/src/universe/resolution_world_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -909,12 +909,6 @@ class ResolutionWorldBuilderImpl extends WorldBuilderBase
}
}

@override
Iterable<ClassEntity> allMixinUsesOf(ClassEntity cls) {
Iterable<ClassEntity> uses = _classHierarchyBuilder.mixinUses[cls];
return uses != null ? uses : const <ClassEntity>[];
}

@override
void registerUsedElement(MemberEntity element) {
if (element.isInstanceMember && !element.isAbstract) {
Expand Down
3 changes: 0 additions & 3 deletions pkg/compiler/lib/src/world.dart
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,6 @@ abstract class OpenWorld implements World {

KClosedWorld closeWorld(DiagnosticReporter reporter);

/// Returns an iterable over all mixin applications that mixin [cls].
Iterable<ClassEntity> allMixinUsesOf(ClassEntity cls);

/// Returns `true` if [member] is inherited into a subtype of [type].
///
/// For instance:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ Future<CompiledData<T>> computeData<T>(Uri entryPoint,
}

dynamic closedWorld = testFrontend
? compiler.resolutionWorldBuilder.closedWorldForTesting
? compiler.frontendClosedWorldForTesting
: compiler.backendClosedWorldForTesting;
ElementEnvironment elementEnvironment = closedWorld?.elementEnvironment;
CommonElements commonElements = closedWorld.commonElements;
Expand Down
6 changes: 3 additions & 3 deletions tests/compiler/dart2js/helpers/type_test_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ class TypeEnvironment {
MemberEntity member = _getMember(name, cls);
DartType type;

for (KLocalFunction local in compiler
.resolutionWorldBuilder.closedWorldForTesting.localFunctions) {
for (KLocalFunction local
in compiler.frontendClosedWorldForTesting.localFunctions) {
if (local.memberContext == member) {
type ??= elementEnvironment.getLocalFunctionType(local);
}
Expand Down Expand Up @@ -179,7 +179,7 @@ class TypeEnvironment {

KClosedWorld get kClosedWorld {
assert(!testBackendWorld);
return compiler.resolutionWorldBuilder.closedWorldForTesting;
return compiler.frontendClosedWorldForTesting;
}
}

Expand Down
3 changes: 1 addition & 2 deletions tests/compiler/dart2js/inlining/meta_annotations_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ main() {
CompilationResult result =
await runCompiler(memorySourceFiles: MEMORY_SOURCE_FILES);
Compiler compiler = result.compiler;
KClosedWorld closedWorld =
compiler.resolutionWorldBuilder.closedWorldForTesting;
KClosedWorld closedWorld = compiler.frontendClosedWorldForTesting;
KElementEnvironment elementEnvironment = closedWorld.elementEnvironment;
Expect.isFalse(compiler.compilationFailed, 'Unsuccessful compilation');

Expand Down
2 changes: 1 addition & 1 deletion tests/compiler/dart2js/member_usage/member_usage_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class ClosedWorldDataComputer extends DataComputer<Features> {
{bool verbose: false}) {
KernelFrontendStrategy frontendStrategy = compiler.frontendStrategy;
ResolutionWorldBuilderImpl resolutionWorldBuilder =
compiler.resolutionWorldBuilder;
compiler.resolutionWorldBuilderForTesting;
ir.Member node = frontendStrategy.elementMap.getMemberNode(member);
Features features = new Features();
MemberUsage memberUsage =
Expand Down
2 changes: 1 addition & 1 deletion tests/compiler/dart2js/model/cfe_annotations_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ main(List<String> args) {
}
}

testAll(compiler.resolutionWorldBuilder.closedWorldForTesting.nativeData);
testAll(compiler.frontendClosedWorldForTesting.nativeData);
if (useIr) {
testAll(new NativeDataImpl.fromIr(elementMap, annotationData));
}
Expand Down
6 changes: 3 additions & 3 deletions tests/compiler/dart2js/model/enqueuer_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ main() {}
void checkInvariant(
Enqueuer enqueuer, ElementEnvironment elementEnvironment) {
for (MemberEntity member
in compiler.enqueuer.resolution.processedEntities) {
in compiler.enqueuer.resolutionEnqueuerForTesting.processedEntities) {
Expect.isTrue(
member == elementEnvironment.mainFunction ||
member.library != elementEnvironment.mainLibrary,
Expand Down Expand Up @@ -245,7 +245,7 @@ main() {}
}

compiler.onResolutionQueueEmptyForTesting = () {
Enqueuer enqueuer = compiler.enqueuer.resolution;
Enqueuer enqueuer = compiler.enqueuer.resolutionEnqueuerForTesting;
ElementEnvironment elementEnvironment =
compiler.frontendStrategy.elementEnvironment;
checkInvariant(enqueuer, elementEnvironment);
Expand Down Expand Up @@ -278,7 +278,7 @@ main() {}
await compiler.run(Uri.parse('memory:main.dart'));

checkLiveMembers(
compiler.enqueuer.resolution,
compiler.enqueuer.resolutionEnqueuerForTesting,
compiler.frontendStrategy.elementEnvironment,
test.expectedLiveResolutionMap);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ void main() {
return env.getElement(name);
});
Iterable<ClassEntity> actualClasses = env
.compiler.resolutionWorldBuilder.directlyInstantiatedClasses
.compiler.resolutionWorldBuilderForTesting.directlyInstantiatedClasses
.where((c) => c.library == mainLibrary);
Expect.setEquals(
expectedClasses,
Expand Down
2 changes: 1 addition & 1 deletion tests/compiler/dart2js/model/open_world_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ ${liveClasses.map((c) => ' new $c();').join('\n')}
ElementEnvironment elementEnvironment =
compiler.frontendStrategy.elementEnvironment;
nativeBasicData = compiler.frontendStrategy.nativeBasicData;
world = compiler.resolutionWorldBuilder;
world = compiler.resolutionWorldBuilderForTesting;

ClassEntity findClass(String name) {
ClassEntity cls =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,7 @@ method2() {
'Class2': ['c'],
};

KClosedWorld closedWorld =
compiler.resolutionWorldBuilder.closedWorldForTesting;
KClosedWorld closedWorld = compiler.frontendClosedWorldForTesting;
ElementEnvironment elementEnvironment = closedWorld.elementEnvironment;

elementEnvironment.forEachClass(elementEnvironment.mainLibrary,
Expand Down
3 changes: 1 addition & 2 deletions tests/compiler/dart2js/model/strong_mode_impact_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,7 @@ main() {
Expect.isTrue(result.isSuccess);
Compiler compiler = result.compiler;

KClosedWorld closedWorld =
compiler.resolutionWorldBuilder.closedWorldForTesting;
KClosedWorld closedWorld = compiler.frontendClosedWorldForTesting;
ElementEnvironment elementEnvironment = closedWorld.elementEnvironment;

elementEnvironment.forEachLibraryMember(elementEnvironment.mainLibrary,
Expand Down
10 changes: 5 additions & 5 deletions tests/compiler/dart2js/rti/rti_need_test_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ abstract class ComputeValueMixin {

KernelFrontendStrategy get frontendStrategy => compiler.frontendStrategy;
ResolutionWorldBuilder get resolutionWorldBuilder =>
compiler.resolutionWorldBuilder;
compiler.resolutionWorldBuilderForTesting;
RuntimeTypesNeedBuilderImpl get rtiNeedBuilder =>
frontendStrategy.runtimeTypesNeedBuilderForTesting;
RuntimeTypesNeedImpl get rtiNeed =>
Expand Down Expand Up @@ -275,8 +275,8 @@ class RtiNeedDataComputer extends DataComputer<String> {
abstract class IrMixin implements ComputeValueMixin {
@override
MemberEntity getFrontendMember(MemberEntity backendMember) {
ElementEnvironment elementEnvironment = compiler
.resolutionWorldBuilder.closedWorldForTesting.elementEnvironment;
ElementEnvironment elementEnvironment =
compiler.frontendClosedWorldForTesting.elementEnvironment;
LibraryEntity frontendLibrary =
elementEnvironment.lookupLibrary(backendMember.library.canonicalUri);
if (backendMember.enclosingClass != null) {
Expand All @@ -300,8 +300,8 @@ abstract class IrMixin implements ComputeValueMixin {
@override
ClassEntity getFrontendClass(ClassEntity backendClass) {
if (backendClass.isClosure) return null;
ElementEnvironment elementEnvironment = compiler
.resolutionWorldBuilder.closedWorldForTesting.elementEnvironment;
ElementEnvironment elementEnvironment =
compiler.frontendClosedWorldForTesting.elementEnvironment;
LibraryEntity frontendLibrary =
elementEnvironment.lookupLibrary(backendClass.library.canonicalUri);
return elementEnvironment.lookupClass(frontendLibrary, backendClass.name);
Expand Down

0 comments on commit 4eae396

Please sign in to comment.