Support caching impacts with the kernel frontend. This is needed by deferred

loading.

To make this possible, this CL explicitly models the impact cache and deleter.

Change-Id: I444625a7a14155d9c530a390854a42d277055aaa
Reviewed-on: https://dart-review.googlesource.com/18463
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Sigmund Cherem 2017-11-03 17:52:21 +00:00
parent cfa3a809f0
commit c53c2f948d
13 changed files with 100 additions and 34 deletions

View file

@ -89,6 +89,8 @@ abstract class Compiler {
BackendStrategy backendStrategy;
CompilerDiagnosticReporter _reporter;
CompilerResolution _resolution;
Map<Entity, WorldImpact> _impactCache;
ImpactCacheDeleter _impactCacheDeleter;
ParsingContext _parsingContext;
ImpactStrategy impactStrategy = const ImpactStrategy();
@ -122,6 +124,8 @@ abstract class Compiler {
DiagnosticReporter get reporter => _reporter;
Resolution get resolution => _resolution;
Map<Entity, WorldImpact> get impactCache => _impactCache;
ImpactCacheDeleter get impactCacheDeleter => _impactCacheDeleter;
ParsingContext get parsingContext => _parsingContext;
// TODO(zarah): Remove this map and incorporate compile-time errors
@ -192,7 +196,14 @@ abstract class Compiler {
backendStrategy = options.useKernel
? new KernelBackendStrategy(this)
: new ElementBackendStrategy(this);
_resolution = createResolution();
if (options.useKernel) {
_impactCache = <Entity, WorldImpact>{};
_impactCacheDeleter = new _MapImpactCacheDeleter(_impactCache);
} else {
_resolution = createResolution();
_impactCache = _resolution._worldImpactCache;
_impactCacheDeleter = _resolution;
}
if (options.verbose) {
progress = new ProgressImpl(_reporter);
@ -1301,11 +1312,11 @@ class CompilerDiagnosticReporter extends DiagnosticReporter {
}
// TODO(johnniwinther): Move [ResolverTask] here.
class CompilerResolution implements Resolution {
class CompilerResolution implements Resolution, ImpactCacheDeleter {
final Compiler _compiler;
final Map<Element, ResolutionImpact> _resolutionImpactCache =
<Element, ResolutionImpact>{};
final Map<Element, WorldImpact> _worldImpactCache = <Element, WorldImpact>{};
final Map<Entity, WorldImpact> _worldImpactCache = <Entity, WorldImpact>{};
bool retainCachesForTesting = false;
Types _types;
@ -1523,7 +1534,7 @@ class CompilerResolution implements Resolution {
}
@override
void uncacheWorldImpact(Element element) {
void uncacheWorldImpact(covariant Element element) {
assert(element.isDeclaration,
failedAt(element, "Element $element must be the declaration."));
if (retainCachesForTesting) return;
@ -1577,6 +1588,23 @@ class CompilerResolution implements Resolution {
}
}
class _MapImpactCacheDeleter implements ImpactCacheDeleter {
final Map<Entity, WorldImpact> _impactCache;
_MapImpactCacheDeleter(this._impactCache);
bool retainCachesForTesting = false;
void uncacheWorldImpact(Entity element) {
if (retainCachesForTesting) return;
_impactCache.remove(element);
}
void emptyCache() {
if (retainCachesForTesting) return;
_impactCache.clear();
}
}
class _ScriptLoader implements ScriptLoader {
Compiler compiler;
_ScriptLoader(this.compiler);

View file

@ -335,8 +335,7 @@ class DeferredLoadTask extends CompilerTask {
return;
}
WorldImpact worldImpact =
compiler.resolution.getWorldImpact(analyzableElement);
WorldImpact worldImpact = compiler.impactCache[analyzableElement];
compiler.impactStrategy.visitImpact(
analyzableElement,
worldImpact,

View file

@ -88,7 +88,8 @@ abstract class FrontendStrategy {
WorkItemBuilder createResolutionWorkItemBuilder(
NativeBasicData nativeBasicData,
NativeDataBuilder nativeDataBuilder,
ImpactTransformer impactTransformer);
ImpactTransformer impactTransformer,
Map<Entity, WorldImpact> impactCache);
/// Computes the main function from [mainLibrary] adding additional world
/// impact to [impactBuilder].
@ -141,3 +142,19 @@ abstract class FrontendStrategyBase implements FrontendStrategy {
return _nativeBasicData;
}
}
/// Class that deletes the contents of an [WorldImpact] cache.
// TODO(redemption): this can be deleted when we sunset the old front end and
// delete serialization.
abstract class ImpactCacheDeleter {
bool retainCachesForTesting;
/// Removes the [WorldImpact] for [element] from the resolution cache. Later
/// calls to [getWorldImpact] or [computeWorldImpact] returns an empty impact.
void uncacheWorldImpact(Entity element);
/// Removes the [WorldImpact]s for all [Element]s in the resolution cache. ,
/// Later calls to [getWorldImpact] or [computeWorldImpact] returns an empty
/// impact.
void emptyCache();
}

View file

@ -462,6 +462,8 @@ class JavaScriptBackend {
Resolution get resolution => compiler.resolution;
ImpactCacheDeleter get impactCacheDeleter => compiler.impactCacheDeleter;
Target get target => _target;
/// Resolution support for generating table of interceptors and
@ -760,7 +762,10 @@ class JavaScriptBackend {
classHierarchyBuilder,
classQueries),
compiler.frontendStrategy.createResolutionWorkItemBuilder(
nativeBasicData, _nativeDataBuilder, impactTransformer));
nativeBasicData,
_nativeDataBuilder,
impactTransformer,
compiler.impactCache));
}
/// Creates an [Enqueuer] for code generation specific to this backend.
@ -1184,7 +1189,8 @@ class JavaScriptBackend {
{bool supportDeferredLoad: true,
bool supportDumpInfo: true,
bool supportSerialization: true}) {
return new JavaScriptImpactStrategy(resolution, compiler.dumpInfoTask,
return new JavaScriptImpactStrategy(
impactCacheDeleter, compiler.dumpInfoTask,
supportDeferredLoad: supportDeferredLoad,
supportDumpInfo: supportDumpInfo,
supportSerialization: supportSerialization);
@ -1194,13 +1200,13 @@ class JavaScriptBackend {
}
class JavaScriptImpactStrategy extends ImpactStrategy {
final Resolution resolution;
final ImpactCacheDeleter impactCacheDeleter;
final DumpInfoTask dumpInfoTask;
final bool supportDeferredLoad;
final bool supportDumpInfo;
final bool supportSerialization;
JavaScriptImpactStrategy(this.resolution, this.dumpInfoTask,
JavaScriptImpactStrategy(this.impactCacheDeleter, this.dumpInfoTask,
{this.supportDeferredLoad,
this.supportDumpInfo,
this.supportSerialization});
@ -1215,7 +1221,7 @@ class JavaScriptImpactStrategy extends ImpactStrategy {
} else {
impact.apply(visitor);
if (impactSource is Element) {
resolution.uncacheWorldImpact(impactSource);
impactCacheDeleter.uncacheWorldImpact(impactSource);
}
}
} else if (impactUse == DeferredLoadTask.IMPACT_USE) {
@ -1234,7 +1240,7 @@ class JavaScriptImpactStrategy extends ImpactStrategy {
if (impactUse == DeferredLoadTask.IMPACT_USE && !supportSerialization) {
// TODO(johnniwinther): Allow emptying when serialization has been
// performed.
resolution.emptyCache();
impactCacheDeleter.emptyCache();
}
}
}

View file

@ -143,12 +143,14 @@ class KernelFrontEndStrategy extends FrontendStrategyBase {
classQueries);
}
@override
WorkItemBuilder createResolutionWorkItemBuilder(
NativeBasicData nativeBasicData,
NativeDataBuilder nativeDataBuilder,
ImpactTransformer impactTransformer) {
ImpactTransformer impactTransformer,
Map<Entity, WorldImpact> impactCache) {
return new KernelWorkItemBuilder(elementMap, nativeBasicData,
nativeDataBuilder, impactTransformer, closureModels);
nativeDataBuilder, impactTransformer, closureModels, impactCache);
}
ClassQueries createClassQueries() {
@ -166,20 +168,22 @@ class KernelWorkItemBuilder implements WorkItemBuilder {
final ImpactTransformer _impactTransformer;
final NativeMemberResolver _nativeMemberResolver;
final Map<MemberEntity, ScopeModel> closureModels;
final Map<Entity, WorldImpact> impactCache;
KernelWorkItemBuilder(
this._elementMap,
NativeBasicData nativeBasicData,
NativeDataBuilder nativeDataBuilder,
this._impactTransformer,
this.closureModels)
this.closureModels,
this.impactCache)
: _nativeMemberResolver = new KernelNativeMemberResolver(
_elementMap, nativeBasicData, nativeDataBuilder);
@override
WorkItem createWorkItem(MemberEntity entity) {
return new KernelWorkItem(_elementMap, _impactTransformer,
_nativeMemberResolver, entity, closureModels);
_nativeMemberResolver, entity, closureModels, impactCache);
}
}
@ -189,9 +193,15 @@ class KernelWorkItem implements ResolutionWorkItem {
final NativeMemberResolver _nativeMemberResolver;
final MemberEntity element;
final Map<MemberEntity, ScopeModel> closureModels;
final Map<Entity, WorldImpact> impactCache;
KernelWorkItem(this._elementMap, this._impactTransformer,
this._nativeMemberResolver, this.element, this.closureModels);
KernelWorkItem(
this._elementMap,
this._impactTransformer,
this._nativeMemberResolver,
this.element,
this.closureModels,
this.impactCache);
@override
WorldImpact run() {
@ -201,7 +211,12 @@ class KernelWorkItem implements ResolutionWorkItem {
if (closureModel != null) {
closureModels[element] = closureModel;
}
return _impactTransformer.transformResolutionImpact(impact);
WorldImpact worldImpact =
_impactTransformer.transformResolutionImpact(impact);
if (impactCache != null) {
impactCache[element] = impact;
}
return worldImpact;
}
}

View file

@ -153,7 +153,8 @@ class ResolutionFrontEndStrategy extends FrontendStrategyBase
WorkItemBuilder createResolutionWorkItemBuilder(
NativeBasicData nativeBasicData,
NativeDataBuilder nativeDataBuilder,
ImpactTransformer impactTransformer) {
ImpactTransformer impactTransformer,
Map<Entity, WorldImpact> impactCache) {
return new ResolutionWorkItemBuilder(_compiler.resolution);
}

View file

@ -201,7 +201,7 @@ Future<ResultKind> mainInternal(List<String> args,
memorySourceFiles: memorySourceFiles,
diagnosticHandler: collector,
options: [Flags.analyzeOnly, Flags.enableAssertMessage]);
compiler1.resolution.retainCachesForTesting = true;
compiler1.impactCacheDeleter.retainCachesForTesting = true;
await compiler1.run(entryPoint);
if (collector.crashes.isNotEmpty) {
print('Skipping due to crashes.');

View file

@ -118,7 +118,7 @@ Future<ResultKind> mainInternal(List<String> args,
diagnosticHandler: collector,
options: [Flags.analyzeOnly, Flags.enableAssertMessage]);
ElementResolutionWorldBuilder.useInstantiationMap = true;
compiler1.resolution.retainCachesForTesting = true;
compiler1.impactCacheDeleter.retainCachesForTesting = true;
await compiler1.run(entryPoint);
if (collector.crashes.isNotEmpty) {
print('Skipping due to crashes.');

View file

@ -395,7 +395,7 @@ Future<ResultKind> runTest(
outputProvider: collector1,
options: <String>[]..addAll(commonOptions)..addAll(options));
ElementResolutionWorldBuilder.useInstantiationMap = true;
compiler1.resolution.retainCachesForTesting = true;
compiler1.impactCacheDeleter.retainCachesForTesting = true;
await compiler1.run(entryPoint);
if (collector.crashes.isNotEmpty) {
print('Skipping due to crashes.');

View file

@ -54,7 +54,7 @@ Future<List<CompileFunction>> compileMultiple(List<String> sources) async {
Flags.useKernel
]);
ElementResolutionWorldBuilder.useInstantiationMap = true;
compiler.resolution.retainCachesForTesting = true;
compiler.impactCacheDeleter.retainCachesForTesting = true;
await compiler.run(entryPoint);
return compiler;
});
@ -75,7 +75,7 @@ Future<Pair<Compiler, Compiler>> analyzeOnly(
entryPoint: entryPoint,
memorySourceFiles: memorySourceFiles,
options: [Flags.analyzeAll, Flags.enableAssertMessage]);
compiler.resolution.retainCachesForTesting = true;
compiler.impactCacheDeleter.retainCachesForTesting = true;
await compiler.run(entryPoint);
if (printSteps) {
@ -86,7 +86,7 @@ Future<Pair<Compiler, Compiler>> analyzeOnly(
memorySourceFiles: memorySourceFiles,
options: [Flags.analyzeOnly, Flags.enableAssertMessage, Flags.useKernel]);
ElementResolutionWorldBuilder.useInstantiationMap = true;
compiler2.resolution.retainCachesForTesting = true;
compiler2.impactCacheDeleter.retainCachesForTesting = true;
await compiler2.run(entryPoint);
return new Pair<Compiler, Compiler>(compiler, compiler2);
}
@ -156,7 +156,7 @@ Future<Compiler> compileWithDill(
diagnosticHandler: diagnosticHandler,
outputProvider: compilerOutput);
ElementResolutionWorldBuilder.useInstantiationMap = true;
compiler.resolution.retainCachesForTesting = true;
compiler.impactCacheDeleter.retainCachesForTesting = true;
if (beforeRun != null) {
beforeRun(compiler);
}

View file

@ -34,14 +34,14 @@ Future check(SerializedData serializedData, Uri entryPoint,
bool verbose: false}) async {
Compiler compilerNormal =
compilerFor(memorySourceFiles: sourceFiles, options: [Flags.analyzeAll]);
compilerNormal.resolution.retainCachesForTesting = true;
compilerNormal.impactCacheDeleter.retainCachesForTesting = true;
await compilerNormal.run(entryPoint);
Compiler compilerDeserialized = compilerFor(
memorySourceFiles: serializedData.toMemorySourceFiles(sourceFiles),
resolutionInputs: serializedData.toUris(),
options: [Flags.analyzeAll]);
compilerDeserialized.resolution.retainCachesForTesting = true;
compilerDeserialized.impactCacheDeleter.retainCachesForTesting = true;
await compilerDeserialized.run(entryPoint);
checkAllImpacts(compilerNormal, compilerDeserialized, verbose: verbose);

View file

@ -69,7 +69,7 @@ Future checkModels(Uri entryPoint,
Compiler compilerNormal = await measure(title, 'compile normal', () async {
Compiler compilerNormal = compilerFor(
memorySourceFiles: sourceFiles, options: [Flags.analyzeOnly]);
compilerNormal.resolution.retainCachesForTesting = true;
compilerNormal.impactCacheDeleter.retainCachesForTesting = true;
await compilerNormal.run(entryPoint);
ElementEnvironment elementEnvironment =
compilerNormal.frontendStrategy.elementEnvironment;
@ -83,7 +83,7 @@ Future checkModels(Uri entryPoint,
memorySourceFiles: sourceFiles,
resolutionInputs: resolutionInputs,
options: [Flags.analyzeOnly]);
compilerDeserialized.resolution.retainCachesForTesting = true;
compilerDeserialized.impactCacheDeleter.retainCachesForTesting = true;
await compilerDeserialized.run(entryPoint);
ElementEnvironment elementEnvironment =
compilerDeserialized.frontendStrategy.elementEnvironment;

View file

@ -36,14 +36,14 @@ Future check(SerializedData serializedData, Uri entryPoint,
[Map<String, String> sourceFiles = const <String, String>{}]) async {
Compiler compilerNormal =
compilerFor(memorySourceFiles: sourceFiles, options: [Flags.analyzeAll]);
compilerNormal.resolution.retainCachesForTesting = true;
compilerNormal.impactCacheDeleter.retainCachesForTesting = true;
await compilerNormal.run(entryPoint);
Compiler compilerDeserialized = compilerFor(
memorySourceFiles: serializedData.toMemorySourceFiles(sourceFiles),
resolutionInputs: serializedData.toUris(),
options: [Flags.analyzeAll]);
compilerDeserialized.resolution.retainCachesForTesting = true;
compilerDeserialized.impactCacheDeleter.retainCachesForTesting = true;
await compilerDeserialized.run(entryPoint);
checkAllResolvedAsts(compilerNormal, compilerDeserialized, verbose: true);